<pre class='metadata'>
Title: WebGPU
Shortname: webgpu
Level: 1
Status: w3c/ED
Group: webgpu
URL: https://gpuweb.github.io/gpuweb

!Participate: <a href="https://github.com/gpuweb/gpuweb/issues/new">File an issue</a> (<a href="https://github.com/gpuweb/gpuweb/issues">open issues</a>)

Editor: Dzmitry Malyshau, Mozilla https://www.mozilla.org, dmalyshau@mozilla.com
Editor: Justin Fan, Apple https://www.apple.com, justin_fan@apple.com
Editor: Kai Ninomiya, Google http://www.google.com, kainino@google.com
Abstract: WebGPU exposes an API for performing operations, such as rendering and computation, on a Graphics Processing Unit.
Markup Shorthands: markdown yes
Markup Shorthands: dfn yes
Markup Shorthands: idl yes
Markup Shorthands: css no
Assume Explicit For: yes
</pre>

<pre class='anchors'>
spec: ECMA-262; urlPrefix: https://tc39.github.io/ecma262/
    type: dfn
        text: agent; url: agent
spec: webidl; urlPrefix: https://heycam.github.io/webidl/#
    type: dfn
        text: resolve; url: resolve
</pre>

<style>
/* Make <dl> blocks more distinct from their surroundings. */
dl {
    border-left: thin solid #f3e48c;
    padding-left: .5em;
}

/* <p> by default has these margins. Update ul/ol/dl to match,
 * since they are also put in places where paragraphs go. */
p, ul, ol, dl {
    margin: 1em 0;
}

/* Box for Valid Usage requirements. */
div.validusage {
    padding: .5em;
    border: thin solid #88e !important;
    border-radius: .5em;
}
/*
 * If the Valid Usage requirements are the first child of a *-timeline block give it a larger top
 * margin to prevent the block labels from overlapping.
 */
.content-timeline>.validusage:first-child,
.device-timeline>.validusage:first-child,
.queue-timeline>.validusage:first-child {
    margin-top: 1.5em;
}

/*
 * Boxes for steps that occur on a particular timeline.
 */
div.content-timeline, div.device-timeline, div.queue-timeline {
    padding: .5em;
    border-radius: .5em;
}
.content-timeline {
    background: rgba(0, 255, 0, 0.05);
}
.device-timeline {
    background: rgba(255, 0, 0, 0.05);
}
.queue-timeline {
    background: rgba(255, 0, 255, 0.05);
}

/*
 * Stylistic labels, for clarity of presentation of these blocks.
 *
 * NOTE: This text is non-accessible and non-selectable; surrounding
 * text must also explain the context.
 */
.validusage, .content-timeline, .device-timeline, .queue-timeline {
    position: relative;
}
.validusage::before,
.content-timeline::before,
.device-timeline::before,
.queue-timeline::before {
    font-weight: bold;
    font-style: italic;
    font-size: 130%;
    color: rgba(0, 0, 0, 0.15);
    position: absolute;
    right: .3em;
    top: -.1em;
}
.validusage::before {
    content: "Valid Usage";
}
.content-timeline::before {
    content: "Content Timeline";
}
.device-timeline::before {
    content: "Device Timeline";
}
.queue-timeline::before {
    content: "Queue Timeline";
}

/*
 * Ensure that argumentdef blocks don't overflow algorithm section borders. This is made far harder
 * than it needs to be because the top-level W3C stylesheet has several @media + min-width variants
 * that mark themselves as !important and then proceed to do the wrong thing.
 */
@media screen and (min-width: 78em) {
    body:not(.toc-inline) .algorithm .overlarge {
        margin-right: auto !important;
    }
}
@media screen and (min-width: 90em) {
    body:not(.toc-inline) .algorithm .overlarge {
        margin-right: auto !important;
    }
}
.algorithm .overlarge {
    margin-right: auto !important;
}
/*
 * The default algorithm style has a caption that doesn't suit this spec's
 * formatting particularly well. Hide it.
 */
.algorithm .argumentdef {
    margin-top: 0;
}
.algorithm .argumentdef>caption {
    display: none;
}
</style>


# Introduction # {#intro}

*This section is non-normative.*

[Graphics Processing Units](https://en.wikipedia.org/wiki/Graphics_processing_unit), or GPUs for short,
have been essential in enabling rich rendering and computational applications in personal computing.
WebGPU is an API that exposes the capabilities of GPU hardware for the Web.
The API is designed from the ground up to efficiently map to the
[Vulkan](https://www.khronos.org/vulkan/),
[Direct3D 12](https://docs.microsoft.com/en-us/windows/win32/direct3d12/what-is-directx-12-),
and [Metal](https://developer.apple.com/metal/) native GPU APIs.
WebGPU is not related to [WebGL](https://www.khronos.org/webgl/) and does not explicitly target OpenGL ES.

WebGPU sees physical GPU hardware as {{GPUAdapter}}s. It provides a connection to an adapter via
{{GPUDevice}}, which manages resources, and the device's {{GPUQueue}}s, which execute commands.
{{GPUDevice}} may have its own memory with high-speed access to the processing units.
{{GPUBuffer}} and {{GPUTexture}} are the <dfn dfn>physical resources</dfn> backed by GPU memory.
{{GPUCommandBuffer}} and {{GPURenderBundle}} are containers for user-recorded commands.
{{GPUShaderModule}} contains [=shader=] code. The other resources,
such as {{GPUSampler}} or {{GPUBindGroup}}, configure the way [=physical resources=] are used by the GPU.

GPUs execute commands encoded in {{GPUCommandBuffer}}s by feeding data through a [=pipeline=],
which is a mix of fixed-function and programmable stages. Programmable stages execute
<dfn dfn>shaders</dfn>, which are special programs designed to run on GPU hardware.
Most of the state of a [=pipeline=] is defined by
a {{GPURenderPipeline}} or a {{GPUComputePipeline}} object. The state not included
in these [=pipeline=] objects is set during encoding with commands,
such as {{GPUCommandEncoder/beginRenderPass()}} or {{GPURenderPassEncoder/setBlendColor()}}.


# Malicious use considerations # {#malicious-use}

*This section is non-normative.* It describes the risks associated with exposing this API on the Web.

## Security ## {#security}

### CPU-based undefined behavior ### {#security-cpu-ub}

A WebGPU implementation translates the workloads issued by the user into API commands specific
to the target platform. Native APIs specify the valid usage for the commands
(for example, see [vkCreateDescriptorSetLayout](https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkCreateDescriptorSetLayout.html))
and generally don't guarantee any outcome if the valid usage rules are not followed.
This is called "undefined behavior", and it can be exploited by an attacker to access memory
they don't own, or force the driver to execute arbitrary code.

In order to disallow insecure usage, the range of allowed WebGPU behaviors is defined for any input.
An implementation has to validate all the input from the user and only reach the driver
with the valid workloads. This document specifies all the error conditions and handling semantics.
For example, specifying the same buffer with intersecting ranges in both "source" and "destination"
of {{GPUCommandEncoder/copyBufferToBuffer()}} results in {{GPUCommandEncoder}}
generating an error, and no other operation occurring.

See [[#errors-and-debugging]] for more information about error handling.

## GPU-based undefined behavior ## {#security-gpu-ub}

WebGPU [=shader=]s are executed by the compute units inside GPU hardware. In native APIs,
some of the shader instructions may result in undefined behavior on the GPU.
In order to address that, the shader instruction set and its defined behaviors are
strictly defined by WebGPU. When a shader is provided to {{GPUDevice/createShaderModule()}},
the WebGPU implementation has to validate it
before doing any translation (to platform-specific shaders) or transformation passes.

## Uninitialized data ## {#security-uninitialized}

Generally, allocating new memory may expose the leftover data of other applications running on the system.
In order to address that, WebGPU conceptually initializes all the resources to zero, although in practice
an implementation may skip this step if it sees the developer initializing the contents manually.
This includes variables and shared threadgroup memory inside shaders.

The precise mechanism of clearing the threadgroup memory can differ between platforms.
If the native API does not provide facilities to clear it, the WebGPU implementation transforms the compute
shader to first do a clear across all threads, synchronize them, and continue executing developer's code.

## Out-of-bounds access in shaders ## {#security-shader}

[=Shader=]s can access [=physical resource=]s either directly
(for example, as a {{GPUBindingType/"uniform-buffer"}}), or via <dfn dfn>texture unit</dfn>s,
which are fixed-function hardware blocks that handle texture coordinate conversions.
Validation on the API side can only guarantee that all the inputs to the shader are provided and
they have the correct usage and types.
The host API side can not guarantee that the data is accessed within bounds
if the [=texture unit=]s are not involved.

Issue: define the host API distinct from the shader API

In order to prevent the shaders from accessing GPU memory an application doesn't own,
the WebGPU implementation may enable a special mode (called "robust buffer access") in the driver
that guarantees that the access is limited to buffer bounds.

Alternatively, an implementation may transform the shader code by inserting manual bounds checks.
When this path is taken, the out-of-bound checks only apply to array indexing. They aren't needed
for plain field access of shader structures due to the {{GPUBindGroupLayoutEntry/minBufferBindingSize}}
validation on the host side.

If the shader attempts to load data outside of [=physical resource=] bounds,
the implementation is allowed to:
  1. return a value at a different location within the resource bounds
  2. return a value vector of "(0, 0, 0, X)" with any "X"
  3. partially discard the draw or dispatch call

If the shader attempts to write data outside of [=physical resource=] bounds,
the implementation is allowed to:
  1. write the value to a different location within the resource bounds
  2. discard the write operation
  3. partially discard the draw or dispatch call

## Invalid data ## {#security-invalid-data}

When uploading [floating-point](https://en.wikipedia.org/wiki/IEEE_754) data from CPU to GPU,
or generating it on the GPU, we may end up with a binary representation that doesn't correspond
to a valid number, such as infinity or NaN (not-a-number). The GPU behavior in this case is
subject to the accuracy of the GPU hardware implementation of the IEEE-754 standard.
WebGPU guarantees that introducing invalid floating-point numbers would only affect the results
of arithmetic computations and will not have other side effects.

### Driver bugs ### {#security-driver-bugs}

GPU drivers are subject to bugs like any other software. If a bug occurs, an attacker
could possibly exploit the incorrect behavior of the driver to get access to unprivileged data.
In order to reduce the risk, the WebGPU working group will coordinate with GPU vendors
to integrate the WebGPU Conformance Test Suite (CTS) as part of their driver testing process,
like it was done for WebGL.
WebGPU implementations are expected to have workarounds for some of the discovered bugs,
and disable WebGPU on drivers with known bugs that can't be worked around.

### Timing attacks ### {#security-timing}

WebGPU is designed for multi-threaded use via Web Workers. Some of the objects,
like {{GPUBuffer}}, have shared state which can be simultaneously accessed.
This allows race conditions to occur, similar to those of accessing a SharedArrayBuffer
from multiple Web Workers, which makes the thread scheduling observable
and allows the creation of high-precision timers.
The theoretical attack vectors are a subset of those of SharedArrayBuffer.

WebGPU also specifies the {{GPUExtensionName/"timestamp-query"}} extension, which
provides high precision timing of GPU operations. The extension is optional, and a WebGPU
implementation may limit its exposure only to those scenarios that are trusted. Alternatively,
the timing query results could be processed by a compute shader and aligned to a lower precision.

### Row hammer attacks ### {#security-rowhammer}

[Row hammer](https://en.wikipedia.org/wiki/Row_hammer) is a class of attacks that exploit the
leaking of states in DRAM cells. It could be used [on GPU](https://www.vusec.net/projects/glitch/).
WebGPU does not have any specific mitigations in place, and relies on platform-level solutions,
such as reduced memory refresh intervals.

## Denial of service ## {#security-dos}

WebGPU applications have access to GPU memory and compute units. A WebGPU implementation may limit
the available GPU memory to an application, in order to keep other applications responsive.
For GPU processing time, a WebGPU implementation may set up "watchdog" timer that makes sure an
application doesn't cause GPU unresponsiveness for more than a few seconds.
These measures are similar to those used in WebGL.

## Workload identification ## {#security-workload-identification}

WebGPU provides access to constrained global resources shared between different programs
(and web pages) running on the same machine. An application can try to indirectly probe
how constrained these global resources are, in order to reason about workloads performed
by other open web pages, based on the patterns of usage of these shared resources.
These issues are generally analogous to issues with Javascript,
such as system memory and CPU execution throughput. WebGPU does not provide any additional
mitigations for this.

### Memory resources ### {#security-memory-resources}

WebGPU exposes fallible allocations from machine-global memory heaps, such as VRAM.
This allows for probing the size of the system's remaining available memory
(for a given heap type) by attempting to allocate and watching for allocation failures.

GPUs internally have one or more (typically only two) heaps of memory
shared by all running applications. When a heap is depleted, WebGPU would fail to create a resource.
This is observable, which may allow a malicious application to guess what heaps
are used by other applications, and how much they allocate from them.

### Computation resources ### {#security-computation-resources}

If one site uses WebGPU at the same time as another, it may observe the increase
in time it takes to process some work. For example, if a site constantly submits
compute workloads and tracks fences for their completion,
it may observe that something else also started using the GPU.

A GPU has many parts that can be tested independently, such as the arithmetic units,
texture sampling units, atomic units, etc. A malicious application may sense when
some of these units are stressed, and attempt to guess the workload of another
application by analyzing the stress patterns. This is analogous to the realities
of CPU execution of Javascript.

## Privacy ## {#security-privacy}

### Machine-specific limits ### {#security-machine-limits}

WebGPU can expose a lot of detail on the underlying GPU architecture and the device geometry.
This includes available physical adapters, many limits on the GPU and CPU resources
that could be used (such as the maximum texture size), and any optional hardware-specific
features or extensions that are available.

WebGPU is designed to have a strong baseline for the limits. This makes it viable (unlike WebGL)
to *only* expose the baseline limits, trivially reducing the fingerprinting surface.
The implementations may decide to only expose the baseline even if the hardware is more capable,
or to support a limited number of higher-capable feature sets.

### Machine-specific artifacts ### {#security-machine-artifacts}

WebGPU doesn't specify some of the hardware behavior down to the expected bit values,
providing some leeway for the platforms to differentiate. This applies to rasterization coverage
and patterns, interpolation precision of the varyings between shader stages, compute unit scheduling,
and more aspects of execution.

The specification doesn't have mitigations to hide these differences in place.
However our testing has shown that these fingerprintable artifacts
are generally consistent for each hardware vendor's GPUs.
For example, while it's possible to identify rasterization differences between Intel and AMD hardware,
it becomes much harder to differentiate between generations of AMD GPUs.

Privacy-critical applications and users should utilize software implementations to eliminate such artifacts.

### Machine-specific performance ### {#security-machine-performance}

Another factor for differentiating users is measuring the performance of specific
operations on the GPU. Even with low precision timing, repeated execution of an operation
can show if the user's machine is fast at specific workloads.
This is a fairly common vector (present in both WebGL and Javascript),
but it's also low-signal and relatively intractable to truly normalize.


# Fundamentals # {#fundamentals}

## Conventions ## {#conventions}

### Dot Syntax ### {#dot-syntax}

In this specification, the `.` ("dot") syntax, common in programming languages, is used.
The phrasing "`Foo.Bar`" means "the `Bar` member of the value (or interface) `Foo`."

For example, where `buffer` is a {{GPUBuffer}}, `buffer.[[device]].[[adapter]]` means
"the `[[adapter]]` internal slot of the `[[device]]` internal slot of `buffer`.

### Internal Objects ### {#webgpu-internal-objects}

An <dfn dfn>internal object</dfn> is a conceptual, non-exposed WebGPU object.
[=Internal objects=] track the state of an API object and hold any underlying implementation.
If the state of a particular [=internal object=] can change in parallel from multiple [=agents=],
those changes are always atomic with respect to all [=agents=].

Note: An "[=agent=]" refers to a JavaScript "thread" (i.e. main thread, or Web Worker).

### WebGPU Interfaces ### {#webgpu-interfaces}

A <dfn dfn>WebGPU interface</dfn> is an exposed interface which encapsulates an [=internal object=].
It provides the interface through which the [=internal object=]'s state is changed.

As a matter of convention, if a [=WebGPU interface=] is referred to as [=invalid=],
it means that the [=internal object=] it encapsulates is [=invalid=].

Any interface which includes {{GPUObjectBase}} is a [=WebGPU interface=].

<script type=idl>
interface mixin GPUObjectBase {
    attribute USVString? label;
};
</script>

{{GPUObjectBase}} has the following attributes:

<dl dfn-type=attribute dfn-for=GPUObjectBase>
    : <dfn>label</dfn>
    ::
        A label which can be used by development tools (such as error/warning messages,
        browser developer tools, or platform debugging utilities) to identify the underlying
        [=internal object=] to the developer.
        It has no specified format, and therefore cannot be reliably machine-parsed.

        In any given situation, the user agent may or may not choose to use this label.
</dl>

{{GPUObjectBase}} has the following internal slots:

<dl dfn-type=attribute dfn-for=GPUObjectBase>
    : <dfn>\[[device]]</dfn>, of type [=device=], readonly
    ::
        An internal slot holding the [=device=] which owns the [=internal object=].
</dl>

### Object Descriptors ### {#object-descriptors}

An <dfn dfn>object descriptor</dfn> holds the information needed to create an object,
which is typically done via one of the `create*` methods of {{GPUDevice}}.

<script type=idl>
dictionary GPUObjectDescriptorBase {
    USVString label;
};
</script>

{{GPUObjectDescriptorBase}} has the following members:

<dl dfn-type=dict-member dfn-for=GPUObjectDescriptorBase>
    : <dfn>label</dfn>
    ::
        The initial value of {{GPUObjectBase/label|GPUObjectBase.label}}.
</dl>

## Invalid Internal Objects &amp; Contagious Invalidity ## {#invalidity}

If an object is successfully created, it is <dfn dfn>valid</dfn> at that moment.
An [=internal object=] may be <dfn dfn>invalid</dfn>.
It may become [=invalid=] during its lifetime, but it will never become valid again.

<div class=note>
    [=Invalid=] objects result from a number of situations, including:

      - If there is an error in the creation of an object, it is immediately invalid.
        This can happen, for example, if the [=object descriptor=] doesn't describe a valid
        object, or if there is not enough memory to allocate a resource.
      - If an object is explicitly destroyed (e.g. {{GPUBuffer/destroy()|GPUBuffer.destroy()}}),
        it becomes invalid.
      - If the [=device=] that owns an object is lost, the object becomes invalid.
</div>

<div algorithm>
    To determine if a given {{GPUObjectBase}} |object| is <dfn abstract-op>valid to use with</dfn>
    a |targetObject|, run the following steps:

        1. If any of the following conditions are unsatisfied return `false`:
            <div class=validusage>
                - |object| is [=valid=]
                - If |targetObject| is a {{GPUDevice}} |object|.{{GPUObjectBase/[[device]]}} is |targetObject|.
                - Otherwise |object|.{{GPUObjectBase/[[device]]}} is |targetObject|.{{GPUObjectBase/[[device]]}}.
            </div>
        1. Return `true`.
</div>

## Coordinate Systems ## {#coordinate-systems}

WebGPU's coordinate systems match DirectX and Metal's coordinate systems in a graphics pipeline.
  - Y-axis is up in normalized device coordinate (NDC): point(-1.0, -1.0) in NDC is located at the bottom-left corner of NDC.
    In addition, x and y in NDC should be between -1.0 and 1.0 inclusive, while z in NDC should be between 0.0 and 1.0 inclusive.
    Vertices out of this range in NDC will not introduce any errors, but they will be clipped.
  - Y-axis is down in framebuffer coordinate, viewport coordinate and fragment/pixel coordinate:
    origin(0, 0) is located at the top-left corner in these coordinate systems.
  - Window/present coordinate matches framebuffer coordinate.
  - UV of origin(0, 0) in texture coordinate represents the first texel (the lowest byte) in texture memory.


## Programming Model ## {#programming-model}

### Timelines ### {#programming-model-timelines}

*This section is non-normative.*

A computer system with a user agent at the front-end and GPU at the back-end
has components working on different timelines in parallel:

: <dfn dfn>Content timeline</dfn>
:: Associated with the execution of the Web script.
    It includes calling all methods described by this specification.

    <div class=content-timeline>
        Steps executed on the content timeline look like this.
    </div>

: <dfn dfn>Device timeline</dfn>
:: Associated with the GPU device operations
    that are issued by the user agent.
    It includes creation of adapters, devices, and GPU resources
    and state objects, which are typically synchronous operations from the point
    of view of the user agent part that controls the GPU,
    but can live in a separate OS process.

    <div class=device-timeline>
        Steps executed on the device timeline look like this.
    </div>

: <dfn dfn>Queue timeline</dfn>
:: Associated with the execution of operations
    on the compute units of the GPU. It includes actual draw, copy,
    and compute jobs that run on the GPU.

    <div class=queue-timeline>
        Steps executed on the queue timeline look like this.
    </div>

In this specification, asynchronous operations are used when the result value
depends on work that happens on any timeline other than the [=Content timeline=].
They are represented by callbacks and promises in JavaScript.

<div class="example">
{{GPUComputePassEncoder/dispatch(x, y, z)|GPUComputePassEncoder.dispatch()}}:

  1. User encodes a `dispatch` command by calling a method of the
    {{GPUComputePassEncoder}} which happens on the [=Content timeline=].
  2. User issues {{GPUQueue/submit(commandBuffers)|GPUQueue.submit()}} that hands over
    the {{GPUCommandBuffer}} to the user agent, which processes it
    on the [=Device timeline=] by calling the OS driver to do a low-level submission.
  3. The submit gets dispatched by the GPU thread scheduler onto the
    actual compute units for execution, which happens on the [=Queue timeline=].

</div>
<div class="example">
{{GPUDevice/createBuffer(descriptor)|GPUDevice.createBuffer()}}:

  1. User fills out a {{GPUBufferDescriptor}} and creates a {{GPUBuffer}} with it,
    which happens on the [=Content timeline=].
  2. User agent creates a low-level buffer on the [=Device timeline=].

</div>
<div class="example">
{{GPUBuffer/mapAsync()|GPUBuffer.mapAsync()}}:

  1. User requests to map a {{GPUBuffer}} on the [=Content timeline=] and
    gets a promise in return.
  2. User agent checks if the buffer is currently used by the GPU
    and makes a reminder to itself to check back when this usage is over.
  3. After the GPU operating on [=Queue timeline=] is done using the buffer,
    the user agent maps it to memory and [=resolves=] the promise.

</div>

### Memory Model ### {#programming-model-memory}

*This section is non-normative.*

Once a {{GPUDevice}} has been obtained during an application initialization routine,
we can describe the <dfn dfn>WebGPU platform</dfn> as consisting of the following layers:
  1. User agent implementing the specification.
  2. Operating system with low-level native API drivers for this device.
  3. Actual CPU and GPU hardware.

Each layer of the [=WebGPU platform=] may have different memory types
that the user agent needs to consider when implementing the specification:
  - The script-owned memory, such as an {{ArrayBuffer}} created by the script,
    is generally not accessible by a GPU driver.
  - A user agent may have different processes responsible for running
    the content and communication to the GPU driver.
    In this case, it uses inter-process shared memory to transfer data.
  - Dedicated GPUs have their own memory with high bandwidth,
    while integrated GPUs typically share memory with the system.

Most [=physical resources=] are allocated in the memory of type
that is efficient for computation or rendering by the GPU.
When the user needs to provide new data to the GPU,
the data may first need to cross the process boundary in order to reach
the user agent part that communicates with the GPU driver.
Then it may need to be made visible to the driver,
which sometimes requires a copy into driver-allocated staging memory.
Finally, it may need to be transferred to the dedicated GPU memory,
potentially changing the internal layout into one
that is most efficient for GPUs to operate on.

All of these transitions are done by the WebGPU implementation of the user agent.

Note: This example describes the worst case, while in practice
the implementation may not need to cross the process boundary,
or may be able to expose the driver-managed memory directly to
the user behind an `ArrayBuffer`, thus avoiding any data copies.

### Multi-Threading ### {#programming-model-multi-threading}

### Resource Usages ### {#programming-model-resource-usages}

Buffers and textures can be used by the GPU in multiple ways,
which can be split into two groups:

: <dfn dfn>Read-only usage</dfn>s
:: Usages like
    {{GPUBufferUsage/VERTEX|GPUBufferUsage.VERTEX}} or
    {{GPUTextureUsage/SAMPLED|GPUTextureUsage.SAMPLED}}
    don't change the contents of a resource.

: <dfn dfn>Mutating usage</dfn>s
:: Usages like {{GPUBufferUsage/STORAGE|GPUBufferUsage.STORAGE}}
    do change the contents of a resource.

Issue(gpuweb/gpuweb#296): Consider merging all read-only usages.

Textures may consist of separate [=mipmap levels=] and [=array layers=],
which can be used differently at any given time.
Each such <dfn dfn>subresource</dfn> is uniquely identified by a
[=texture=], [=mipmap level=], and
(for {{GPUTextureDimension/2d}} textures only) [=array layer=].

The **main usage rule** is that any [=subresource=]
at any given time can only be in either:
  - a combination of [=read-only usage=]s
  - a single [=mutating usage=]

Enforcing this rule allows the API to limit when data races can occur
when working with memory. That property makes applications written against
WebGPU more likely to run without modification on different platforms.

Generally, when an implementation processes an operation that uses a [=subresource=]
in a different way than its current usage allows, it schedules a transition of the resource
into the new state. In some cases, like within an open {{GPURenderPassEncoder}}, such a
transition is impossible due to the hardware limitations.
We define these places as <dfn dfn>usage scopes</dfn>:
each [=subresource=] must not change usage within the [=usage scope=].

For example, binding the same buffer for {{GPUBufferUsage/STORAGE|GPUBufferUsage.STORAGE}} as well as for
{{GPUBufferUsage/VERTEX|GPUBufferUsage.VERTEX}} within the same {{GPURenderPassEncoder}} would put the encoder
as well as the owning {{GPUCommandEncoder}} into the error state. Since
{{GPUBufferUsage/STORAGE|GPUBufferUsage.STORAGE}} is the only [=mutating usage=] for a buffer
that is valid inside a render pass, if it's present,
this buffer can't be used in any other way within this pass.

The [=subresources=] of textures included in the views provided to
{{GPURenderPassColorAttachmentDescriptor/attachment|GPURenderPassColorAttachmentDescriptor.attachment}} and
{{GPURenderPassColorAttachmentDescriptor/resolveTarget|GPURenderPassColorAttachmentDescriptor.resolveTarget}}
are considered to have {{GPUTextureUsage/OUTPUT_ATTACHMENT}}
for the [=usage scope=] of this render pass.

The <dfn dfn>physical size</dfn> of a {{GPUTexture}} [=subresource=] is the dimension of the {{GPUTexture}}
[=subresource=] in texels that includes the possible extra paddings to form complete [=texel blocks=] in the
[=subresource=].

  - For pixel-based {{GPUTextureFormat}}s, the [=physical size=] is always equal to the size of the [=subresource=]
    used in the sampling hardwares.
  - {{GPUTexture}}s in block-based compressed {{GPUTextureFormat}}s always have a [=mipmap level=] 0 whose {{GPUTexture/[[textureSize]]}}
    is a multiple of the [=texel block size=], but the lower mipmap levels might not be the multiple of the [=texel block size=] and can
    have paddings.

<div class="example">
Considering a {{GPUTexture}} in BC format whose {{GPUTexture/[[textureSize]]}} is {60, 60, 1}, when sampling
the {{GPUTexture}} at [=mipmap level=] 2, the sampling hardware uses {15, 15, 1} as the size of the [=subresource=],
while its [=physical size=] is {16, 16, 1} as the block-compression algorithm can only operate on 4x4 [=texel blocks=].
</div>

Issue(gpuweb/gpuweb#514): Document read-only states for depth views.

### Synchronization ### {#programming-model-synchronization}

For each [=subresource=] of a [=physical resource=], its set of
[=usage flags=] is tracked on the [=Queue timeline=].
<dfn dfn>Usage flags</dfn> are {{GPUBufferUsage}} or {{GPUTextureUsage}} flags,
according to the type of the subresource.

Issue: This section will need to be revised to support multiple queues.

On the [=Queue timeline=], there is an ordered sequence of [=usage scopes=].
Each item on the timeline is contained within exactly one scope.
For the duration of each scope, the set of [=usage flags=] of any given
[=subresource=] is constant.
A [=subresource=] may transition to new usages
at the boundaries between [=usage scope=]s.

This specification defines the following [=usage scopes=]:
  1. an individual command on a {{GPUCommandEncoder}}, such as {{GPUCommandEncoder/copyBufferToTexture()|GPUCommandEncoder.copyBufferToTexture}}.
  2. an individual command on a {{GPUComputePassEncoder}}, such as {{GPUProgrammablePassEncoder/setBindGroup(index, bindGroup, dynamicOffsets)|GPUProgrammablePassEncoder.setBindGroup}}.
  3. the whole {{GPURenderPassEncoder}}.

Note: calling {{GPUProgrammablePassEncoder/setBindGroup(index, bindGroup, dynamicOffsets)|GPUProgrammablePassEncoder.setBindGroup}}
adds the {{GPUBindGroup/[[usedBuffers]]}} and {{GPUBindGroup/[[usedTextures]]}} to the [=usage scope=]
regardless of whether the shader or {{GPUPipelineLayout}} actually depends on these bindings.
Similarly {{GPURenderEncoderBase/setIndexBuffer()|GPURenderEncoderBase.setIndexBuffer}}
add the index buffer to the usage scope (as {{GPUBufferUsage/INDEX|GPUBufferUsage.INDEX}})
regardless of whether the indexed draw calls are used afterwards.

The [=usage scopes=] are validated at {{GPUCommandEncoder/finish()|GPUCommandEncoder.finish}} time.
The implementation performs the <dfn dfn>usage scope validation</dfn> by composing
the set of all [=usage flags=] of each [=subresource=] used in the [=usage scope=].
A {{GPUValidationError}} is generated in the current scope with an appropriate error message
if that union contains a [=mutating usage=] combined with any other usage.


## Core Internal Objects ## {#core-internal-objects}

### Adapters ### {#adapters}

An <dfn dfn>adapter</dfn> represents an implementation of WebGPU on the system.
Each adapter identifies both an instance of a hardware accelerator (e.g. GPU or CPU) and
an instance of a browser's implementation of WebGPU on top of that accelerator.

If an [=adapter=] becomes unavailable, it becomes [=invalid=].
Once invalid, it never becomes valid again.
Any [=devices=] on the adapter, and [=internal objects=] owned by those devices,
also become invalid.

Note:
An [=adapter=] may be a physical display adapter (GPU), but it could also be
a software renderer.
A returned [=adapter=] could refer to different physical adapters, or to
different browser codepaths or system drivers on the same physical adapters.
Applications can hold onto multiple [=adapters=] at once (via {{GPUAdapter}})
(even if some are [=invalid=]),
and two of these could refer to different instances of the same physical
configuration (e.g. if the GPU was reset or disconnected and reconnected).

An [=adapter=] has the following internal slots:

<dl dfn-type=attribute dfn-for=adapter>
    : <dfn>\[[extensions]]</dfn>, of type sequence<{{GPUExtensionName}}>, readonly
    ::
        The extensions which can be used to create devices on this adapter.

    : <dfn>\[[limits]]</dfn>, of type {{GPULimits}}, readonly
    ::
        The [=better|best=] limits which can be used to create devices on this adapter.

        Each adapter limit must be the same or [=better=] than its default value in {{GPULimits}}.
</dl>

[=Adapters=] are exposed via {{GPUAdapter}}.

### Devices ### {#devices}

A <dfn dfn>device</dfn> is the logical instantiation of an [=adapter=],
through which [=internal objects=] are created.
It can be shared across multiple [=agents=] (e.g. dedicated workers).

A [=device=] is the exclusive owner of all [=internal objects=] created from it:
when the [=device=] is lost, it and all objects created on it (directly, e.g.
{{GPUDevice/createTexture()}}, or indirectly, e.g. {{GPUTexture/createView()}}) become
[=invalid=].

Issue: Define "ownership".

A [=device=] has the following internal slots:

<dl dfn-type=attribute dfn-for=device>
    : <dfn>\[[adapter]]</dfn>, of type [=adapter=], readonly
    ::
        The [=adapter=] from which this device was created.

    : <dfn>\[[extensions]]</dfn>, of type sequence<{{GPUExtensionName}}>, readonly
    ::
        The extensions which can be used on this device.
        No additional extensions can be used, even if the underlying [=adapter=] can support them.

    : <dfn>\[[limits]]</dfn>, of type {{GPULimits}}, readonly
    ::
        The limits which can be used on this device.
        No [=better=] limits can be used, even if the underlying [=adapter=] can support them.
</dl>

<div algorithm>
    When <dfn dfn>a new device</dfn> |device| is created from [=adapter=] |adapter|
    with {{GPUDeviceDescriptor}} |descriptor|:

      - Set |device|.{{device/[[adapter]]}} to |adapter|.

      - Set |device|.{{device/[[extensions]]}} to |descriptor|.{{GPUDeviceDescriptor/extensions}}.

      - Set |device|.{{device/[[limits]]}} to |descriptor|.{{GPUDeviceDescriptor/limits}}.
</div>

[=Devices=] are exposed via {{GPUDevice}}.

## Optional Capabilities ## {#optional-capabilities}

### Limits ### {#limits}

### Extensions ### {#extensions}


# Initialization # {#initialization}

## Examples ## {#initialization-examples}

Issue:
Need a robust example like the one in ErrorHandling.md, which handles all situations.
Possibly also include a simple example with no handling.

## navigator.gpu ## {#navigator-gpu}

A {{GPU}} object is available via `navigator.gpu` on the {{Window}}:

<script type=idl>
[Exposed=Window]
partial interface Navigator {
    [SameObject] readonly attribute GPU gpu;
};
</script>

... as well as on dedicated workers:

<script type=idl>
[Exposed=DedicatedWorker]
partial interface WorkerNavigator {
    [SameObject] readonly attribute GPU gpu;
};
</script>

## GPU ## {#gpu-interface}

<dfn interface>GPU</dfn> is the entry point to WebGPU.

<script type=idl>
[Exposed=(Window, DedicatedWorker)]
interface GPU {
    Promise<GPUAdapter?> requestAdapter(optional GPURequestAdapterOptions options = {});
};
</script>

{{GPU}} has the following methods:

<dl dfn-type=method dfn-for=GPU>
    : <dfn>requestAdapter(options)</dfn>
    ::

        Requests an [=adapter=] from the user agent.
        The user agent chooses whether to return an adapter, and, if so,
        chooses according to the provided options.

        <div algorithm=GPU.requestAdapter>
            **Called on:** {{GPU}} |this|.

            **Arguments:**
            <pre class=argumentdef for="GPU/requestAdapter(options)">
                options:
            </pre>

            **Returns:** `Promise<{{GPUAdapter}}?>`.

            1. Let |promise| be [=a new promise=].
            1. Issue the following steps on the [=Device timeline=] of |this|:
                <div class=device-timeline>
                    1. If the user agent chooses to return an adapter:

                        1. The user agent chooses an [=adapter=] |adapter| according to the rules in
                            [[#adapter-selection]].

                        1. |promise| [=resolves=] with a new {{GPUAdapter}} encapsulating |adapter|.

                    1. Otherwise, |promise| [=resolves=] with `null`.
                </div>
            1. Return |promise|.

            <!-- If we add ways to make invalid adapter requests (aside from those
                 that violate IDL rules), specify that they reject the promise. -->
        </div>
</dl>

### Adapter Selection ### {#adapter-selection}

<dfn dictionary>GPURequestAdapterOptions</dfn>
provides hints to the user agent indicating what
configuration is suitable for the application.

<script type=idl>
dictionary GPURequestAdapterOptions {
    GPUPowerPreference powerPreference;
};
</script>

<script type=idl>
enum GPUPowerPreference {
    "low-power",
    "high-performance"
};
</script>

{{GPURequestAdapterOptions}} has the following members:

<dl dfn-type=dict-member dfn-for=GPURequestAdapterOptions>
    : <dfn>powerPreference</dfn>
    ::
        Optionally provides a hint indicating what class of [=adapter=] should be selected from
        the system's available adapters.

        The value of this hint may influence which adapter is chosen, but it must not
        influence whether an adapter is returned or not.

        Note:
        The primary utility of this hint is to influence which GPU is used in a multi-GPU system.
        For instance, some laptops have a low-power integrated GPU and a high-performance
        discrete GPU.

        Note:
        Depending on the exact hardware configuration, such as battery status and attached displays
        or removable GPUs, the user agent may select different [=adapters=] given the same power
        preference.
        Typically, given the same hardware configuration and state and
        `powerPreference`, the user agent is likely to select the same adapter.

        It must be one of the following values:

        <dl dfn-type=enum-value dfn-for=GPUPowerPreference>
            : `undefined` (or not present)
            ::
                Provides no hint to the user agent.

            : <dfn>"low-power"</dfn>
            ::
                Indicates a request to prioritize power savings over performance.

                Note:
                Generally, content should use this if it is unlikely to be constrained by drawing
                performance; for example, if it renders only one frame per second, draws only relatively
                simple geometry with simple shaders, or uses a small HTML canvas element.
                Developers are encouraged to use this value if their content allows, since it may
                significantly improve battery life on portable devices.

            : <dfn>"high-performance"</dfn>
            ::
                Indicates a request to prioritize performance over power consumption.

                Note:
                By choosing this value, developers should be aware that, for [=devices=] created on the
                resulting adapter, user agents are more likely to force device loss, in order to save
                power by switching to a lower-power adapter.
                Developers are encouraged to only specify this value if they believe it is absolutely
                necessary, since it may significantly decrease battery life on portable devices.
        </dl>
</dl>

## <dfn interface>GPUAdapter</dfn> ## {#gpu-adapter}

A {{GPUAdapter}} encapsulates an [=adapter=],
and describes its capabilities (extensions and limits).

To get a {{GPUAdapter}}, use {{GPU/requestAdapter()}}.

<script type=idl>
interface GPUAdapter {
    readonly attribute DOMString name;
    readonly attribute FrozenArray<GPUExtensionName> extensions;
    //readonly attribute GPULimits limits; Don't expose higher limits for now.

    Promise<GPUDevice?> requestDevice(optional GPUDeviceDescriptor descriptor = {});
};
</script>

{{GPUAdapter}} has the following attributes:

<dl dfn-type=attribute dfn-for=GPUAdapter>
    : <dfn>name</dfn>
    ::
        A human-readable name identifying the adapter.
        The contents are implementation-defined.

    : <dfn>extensions</dfn>
    ::
        Accessor for `this`.{{GPUAdapter/[[adapter]]}}.{{adapter/[[extensions]]}}.
</dl>

{{GPUAdapter}} has the following internal slots:

<dl dfn-type=attribute dfn-for=GPUAdapter>
    : <dfn>\[[adapter]]</dfn>, of type [=adapter=], readonly
    ::
        The [=adapter=] to which this {{GPUAdapter}} refers.
</dl>

{{GPUAdapter}} has the following methods:

<dl dfn-type=method dfn-for=GPUAdapter>
    : <dfn>requestDevice(descriptor)</dfn>
    ::
        Requests a [=device=] from the [=adapter=].

        <div algorithm=GPUAdapter.requestDevice>
            **Called on:** {{GPUAdapter}} |this|.

            **Arguments:**
            <pre class=argumentdef for="GPUAdapter/requestDevice(descriptor)">
                |descriptor|:
            </pre>

            **Returns:** `Promise<{{GPUDevice}}?>`.

            1. Let |promise| be [=a new promise=].
            1. Issue the following steps to the [=Device timeline=]:
                <div class=device-timeline>
                    1. If any of the following conditions are unsatisfied,
                        [=reject=] |promise| with an {{OperationError}} and stop.

                        <div class=validusage>
                            - The set of {{GPUExtensionName}} values in
                                |descriptor|.{{GPUDeviceDescriptor/extensions}}
                                is a subset of those in
                                |adapter|.{{adapter/[[extensions]]}}.

                            - For each type of limit in {{GPULimits}},
                                the value of that limit in
                                |descriptor|.{{GPUDeviceDescriptor/limits}}
                                is no [=better=] than the value of that limit in
                                |adapter|.{{adapter/[[limits]]}}.

                            where |adapter| is |this|.{{GPUAdapter/[[adapter]]}}.
                        </div>

                    1. If the user agent cannot fulfill the request,
                        [=resolve=] |promise| to `null` and stop.

                    1. [=Resolve=] |promise| to a new {{GPUDevice}} object encapsulating
                        [=a new device=] with the capabilities described by |descriptor|.
                </div>
            1. Return |promise|.

        </div>
</dl>

### <dfn dictionary>GPUDeviceDescriptor</dfn> ### {#gpudevicedescriptor}

{{GPUDeviceDescriptor}} describes a device request.

<script type=idl>
dictionary GPUDeviceDescriptor : GPUObjectDescriptorBase {
    sequence<GPUExtensionName> extensions = [];
    GPULimits limits = {};
};
</script>

{{GPUDeviceDescriptor}} has the following members:

<dl dfn-type=dict-member dfn-for=GPUDeviceDescriptor>
    : <dfn>extensions</dfn>
    ::
        The set of {{GPUExtensionName}} values in this sequence defines the exact set of
        extensions that must be enabled on the device.

    : <dfn>limits</dfn>
    ::
        Defines the exact limits that must be enabled on the device.
</dl>

#### <dfn enum>GPUExtensionName</dfn> #### {#gpuextensionname}

Each {{GPUExtensionName}} identifies a set of functionality which, if available,
allows additional usages of WebGPU that would have otherwise been invalid.

<script type=idl>
enum GPUExtensionName {
    "texture-compression-bc",
    "pipeline-statistics-query",
    "timestamp-query",
    "depth-clamping"
};
</script>

<dl dfn-type=enum-value dfn-for=GPUExtensionName>
    : <dfn>"texture-compression-bc"</dfn>
    ::
        Issue: Write a spec section for this, and link to it.
</dl>

#### <dfn dictionary>GPULimits</dfn> #### {#gpulimits}

{{GPULimits}} describes various limits in the usage of WebGPU on a device.

One limit value may be <dfn dfn>better</dfn> than another.
For each limit, "better" is defined.

Note:
Setting "better" limits may not necessarily be desirable.
While they enable strictly more programs to be valid, they may have a performance impact.
Because of this, and to improve portability across devices and implementations,
applications should generally request the "worst" limits that work for their content.

<script type=idl>
dictionary GPULimits {
    GPUSize32 maxBindGroups = 4;
    GPUSize32 maxDynamicUniformBuffersPerPipelineLayout = 8;
    GPUSize32 maxDynamicStorageBuffersPerPipelineLayout = 4;
    GPUSize32 maxSampledTexturesPerShaderStage = 16;
    GPUSize32 maxSamplersPerShaderStage = 16;
    GPUSize32 maxStorageBuffersPerShaderStage = 4;
    GPUSize32 maxStorageTexturesPerShaderStage = 4;
    GPUSize32 maxUniformBuffersPerShaderStage = 12;
    GPUSize32 maxUniformBufferBindingSize = 16384;
};
</script>

<dl dfn-type=dict-member dfn-for=GPULimits>
    : <dfn>maxBindGroups</dfn>
    ::
        The maximum number of {{GPUBindGroupLayout|GPUBindGroupLayouts}}
        allowed in {{GPUPipelineLayoutDescriptor/bindGroupLayouts}}
        when creating a {{GPUPipelineLayout}}.

        Higher is [=better=].

    : <dfn>maxDynamicUniformBuffersPerPipelineLayout</dfn>
    ::
        The maximum number of {{GPUBindGroupLayoutDescriptor/entries}} for which:

          - {{GPUBindGroupLayoutEntry/type}} is {{GPUBindingType/"uniform-buffer"}}, and
          - {{GPUBindGroupLayoutEntry/hasDynamicOffset}} is true,

        across all {{GPUPipelineLayoutDescriptor/bindGroupLayouts}}
        when creating a {{GPUPipelineLayout}}.

        Higher is [=better=].

    : <dfn>maxDynamicStorageBuffersPerPipelineLayout</dfn>
    ::
        The maximum number of {{GPUBindGroupLayoutDescriptor/entries}} for which:

          - {{GPUBindGroupLayoutEntry/type}} is {{GPUBindingType/"storage-buffer"}}, and
          - {{GPUBindGroupLayoutEntry/hasDynamicOffset}} is true,

        across all {{GPUPipelineLayoutDescriptor/bindGroupLayouts}}
        when creating a {{GPUPipelineLayout}}.

        Higher is [=better=].

    : <dfn>maxSampledTexturesPerShaderStage</dfn>
    ::
        For each possible {{GPUShaderStage}} `stage`,
        the maximum number of {{GPUBindGroupLayoutDescriptor/entries}} for which:

          - {{GPUBindGroupLayoutEntry/type}} is {{GPUBindingType/"sampled-texture"}}, and
          - {{GPUBindGroupLayoutEntry/visibility}} includes `stage`,

        across all {{GPUPipelineLayoutDescriptor/bindGroupLayouts}}
        when creating a {{GPUPipelineLayout}}.

        Higher is [=better=].

    : <dfn>maxSamplersPerShaderStage</dfn>
    ::
        For each possible {{GPUShaderStage}} `stage`,
        the maximum number of {{GPUBindGroupLayoutDescriptor/entries}} for which:

          - {{GPUBindGroupLayoutEntry/type}} is {{GPUBindingType/"sampler"}}  or {{GPUBindingType/"comparison-sampler"}}, and
          - {{GPUBindGroupLayoutEntry/visibility}} includes `stage`,

        across all {{GPUPipelineLayoutDescriptor/bindGroupLayouts}}
        when creating a {{GPUPipelineLayout}}.

        Higher is [=better=].

    : <dfn>maxStorageBuffersPerShaderStage</dfn>
    ::
        For each possible {{GPUShaderStage}} `stage`,
        the maximum number of {{GPUBindGroupLayoutDescriptor/entries}} for which:

          - {{GPUBindGroupLayoutEntry/type}} is {{GPUBindingType/"storage-buffer"}}, and
          - {{GPUBindGroupLayoutEntry/visibility}} includes `stage`,

        across all {{GPUPipelineLayoutDescriptor/bindGroupLayouts}}
        when creating a {{GPUPipelineLayout}}.

        Higher is [=better=].

    : <dfn>maxStorageTexturesPerShaderStage</dfn>
    ::
        For each possible {{GPUShaderStage}} `stage`,
        the maximum number of {{GPUBindGroupLayoutDescriptor/entries}} for which:

          - {{GPUBindGroupLayoutEntry/type}} is {{GPUBindingType/"readonly-storage-texture"}} or
            {{GPUBindingType/"writeonly-storage-texture"}}, and
          - {{GPUBindGroupLayoutEntry/visibility}} includes `stage`,

        across all {{GPUPipelineLayoutDescriptor/bindGroupLayouts}}
        when creating a {{GPUPipelineLayout}}.

        Higher is [=better=].

    : <dfn>maxUniformBuffersPerShaderStage</dfn>
    ::
        For each possible {{GPUShaderStage}} `stage`,
        the maximum number of {{GPUBindGroupLayoutDescriptor/entries}} for which:

          - {{GPUBindGroupLayoutEntry/type}} is {{GPUBindingType/uniform-buffer}}, and
          - {{GPUBindGroupLayoutEntry/visibility}} includes `stage`,

        across all {{GPUPipelineLayoutDescriptor/bindGroupLayouts}}
        when creating a {{GPUPipelineLayout}}.

        Higher is [=better=].

    : <dfn>maxUniformBufferBindingSize</dfn>
    ::
        The maximum {{GPUBufferBinding}}.{{GPUBufferBinding/size}} for bindings of type {{GPUBindingType/uniform-buffer}}.

        Higher is [=better=].
</dl>

## <dfn interface>GPUDevice</dfn> ## {#gpu-device}

A {{GPUDevice}} encapsulates a [=device=] and exposes
the functionality of that device.

{{GPUDevice}} is the top-level interface through which [=WebGPU interfaces=] are created.

To get a {{GPUDevice}}, use {{GPUAdapter/requestDevice()}}.

<script type=idl>
[Exposed=(Window, DedicatedWorker), Serializable]
interface GPUDevice : EventTarget {
    [SameObject] readonly attribute GPUAdapter adapter;
    readonly attribute FrozenArray<GPUExtensionName> extensions;
    readonly attribute object limits;

    [SameObject] readonly attribute GPUQueue defaultQueue;

    GPUBuffer createBuffer(GPUBufferDescriptor descriptor);
    GPUTexture createTexture(GPUTextureDescriptor descriptor);
    GPUSampler createSampler(optional GPUSamplerDescriptor descriptor = {});

    GPUBindGroupLayout createBindGroupLayout(GPUBindGroupLayoutDescriptor descriptor);
    GPUPipelineLayout createPipelineLayout(GPUPipelineLayoutDescriptor descriptor);
    GPUBindGroup createBindGroup(GPUBindGroupDescriptor descriptor);

    GPUShaderModule createShaderModule(GPUShaderModuleDescriptor descriptor);
    GPUComputePipeline createComputePipeline(GPUComputePipelineDescriptor descriptor);
    GPURenderPipeline createRenderPipeline(GPURenderPipelineDescriptor descriptor);
    Promise<GPUComputePipeline> createReadyComputePipeline(GPUComputePipelineDescriptor descriptor);
    Promise<GPURenderPipeline> createReadyRenderPipeline(GPURenderPipelineDescriptor descriptor);

    GPUCommandEncoder createCommandEncoder(optional GPUCommandEncoderDescriptor descriptor = {});
    GPURenderBundleEncoder createRenderBundleEncoder(GPURenderBundleEncoderDescriptor descriptor);

    GPUQuerySet createQuerySet(GPUQuerySetDescriptor descriptor);
};
GPUDevice includes GPUObjectBase;
</script>

{{GPUDevice}} has:

  - These attributes:
    <dl dfn-type=attribute dfn-for=GPUDevice>
        : <dfn>adapter</dfn>
        ::
            The {{GPUAdapter}} from which this device was created.

        : <dfn>extensions</dfn>
        ::
            A sequence containing the {{GPUExtensionName}}s of the extensions
            supported by the device (i.e. the ones with which it was created).

        : <dfn>limits</dfn>
        ::
            A {{GPULimits}} object exposing the limits
            supported by the device (i.e. the ones with which it was created).
    </dl>

  - These internal slots:
    <dl dfn-type=attribute dfn-for=GPUDevice>
        : <dfn>\[[device]]</dfn>, of type [=device=], readonly
        ::
            The [=device=] that this {{GPUDevice}} refers to.
    </dl>

  - The methods listed in its WebIDL definition above,
    which are defined elsewhere in this document.

{{GPUDevice}} objects are [=serializable objects=].

<div algorithm>
    <dfn abstract-op>The steps to serialize a GPUDevice object</dfn>,
    given |value|, |serialized|, and |forStorage|, are:
     1. If |forStorage| is true, throw a "{{DataCloneError}}".
     1. Set |serialized|.device to the value of |value|.{{GPUDevice/[[device]]}}.
</div>

<div algorithm>
    <dfn abstract-op>The steps to deserialize a GPUDevice object</dfn>,
    given |serialized| and |value|, are:
     1. Set |value|.{{GPUDevice/[[device]]}} to |serialized|.device.
</div>


# Buffers # {#buffers}

## <dfn interface>GPUBuffer</dfn> ## {#buffer-interface}

Issue: define <dfn dfn>buffer</dfn> (internal object)

A {{GPUBuffer}} represents a block of memory that can be used in GPU operations.
Data is stored in linear layout, meaning that each byte of the allocation can be
addressed by its offset from the start of the {{GPUBuffer}}, subject to alignment
restrictions depending on the operation. Some {{GPUBuffer|GPUBuffers}} can be
mapped which makes the block of memory accessible via an {{ArrayBuffer}} called
its mapping.

{{GPUBuffer|GPUBuffers}} are created via
{{GPUDevice/createBuffer(descriptor)|GPUDevice.createBuffer(descriptor)}}
that returns a new buffer in the [=buffer state/mapped=] or [=buffer state/unmapped=] state.

<script type=idl>
[Serializable]
interface GPUBuffer {
    Promise<void> mapAsync(GPUMapModeFlags mode, optional GPUSize64 offset = 0, optional GPUSize64 size);
    ArrayBuffer getMappedRange(optional GPUSize64 offset = 0, optional GPUSize64 size);
    void unmap();

    void destroy();
};
GPUBuffer includes GPUObjectBase;
</script>

{{GPUBuffer}} has the following internal slots:

<dl dfn-type=attribute dfn-for="GPUBuffer">
    : <dfn>\[[size]]</dfn> of type {{GPUSize64}}.
    ::
        The length of the {{GPUBuffer}} allocation in bytes.

    : <dfn>\[[usage]]</dfn> of type {{GPUBufferUsageFlags}}.
    ::
        The allowed usages for this {{GPUBuffer}}.

    : <dfn>\[[state]]</dfn> of type [=buffer state=].
    ::
        The current state of the {{GPUBuffer}}.

    : <dfn>\[[mapping]]</dfn> of type {{ArrayBuffer}} or {{Promise}} or `null`.
    ::
        The mapping for this {{GPUBuffer}}. The {{ArrayBuffer}} isn't directly accessible
        and is instead accessed through views into it, called the mapped ranges, that are
        stored in {{GPUBuffer/[[mapped_ranges]]}}

        Issue(gpuweb/gpuweb#605): Specify {{GPUBuffer/[[mapping]]}} in term of `DataBlock` similarly
        to `AllocateArrayBuffer`?

    : <dfn>\[[mapping_range]]</dfn> of type `sequence<Number>` or `null`.
    ::
        The range of this {{GPUBuffer}} that is mapped.

    : <dfn>\[[mapped_ranges]]</dfn> of type `sequence<ArrayBuffer>` or `null`.
    ::
        The {{ArrayBuffer}}s returned via {{GPUBuffer/getMappedRange}} to the application. They are tracked
        so they can be detached when {{GPUBuffer/unmap}} is called.

    : <dfn>\[[map_mode]]</dfn> of type {{GPUMapModeFlags}}.
    ::
        The {{GPUMapModeFlags}} of the last call to {{GPUBuffer/mapAsync()}} (if any).
</dl>

Issue: {{GPUBuffer/[[usage]]}} is differently named from {{GPUTexture/[[textureUsage]]}}.
We should make it consistent.

Each {{GPUBuffer}} has a current <dfn dfn>buffer state</dfn> on the [=Content timeline=]
which is one of the following:

 - "<dfn dfn for="buffer state">mapped</dfn>" where the {{GPUBuffer}} is
     available for CPU operations on its content.
 - "<dfn dfn for="buffer state">mapped at creation</dfn>" where the {{GPUBuffer}} was
     just created and is available for CPU operations on its content.
 - "<dfn dfn for="buffer state">mapping pending</dfn>" where the {{GPUBuffer}} is
     being made available for CPU operations on its content.
 - "<dfn dfn for="buffer state">unmapped</dfn>" where the {{GPUBuffer}} is
     available for GPU operations.
 - "<dfn dfn for="buffer state">destroyed</dfn>" where the {{GPUBuffer}} is
     no longer available for any operations except {{GPUBuffer/destroy}}.

Note:
{{GPUBuffer/[[size]]}} and {{GPUBuffer/[[usage]]}} are immutable once the
{{GPUBuffer}} has been created.

<div class=note>
   Note: {{GPUBuffer}} has a state machine with the following states.
    ({{GPUBuffer/[[mapping]]}}, {{GPUBuffer/[[mapping_range]]}},
    and {{GPUBuffer/[[mapped_ranges]]}} are null when not specified.)

     - [=buffer state/unmapped=] and [=buffer state/destroyed=].
     - [=buffer state/mapped=] or [=buffer state/mapped at creation=] with an
        {{ArrayBuffer}} typed {{GPUBuffer/[[mapping]]}}, a sequence of two
        numbers in {{GPUBuffer/[[mapping_range]]}} and a sequence of {{ArrayBuffer}}
        in {{GPUBuffer/[[mapped_ranges]]}}
     - [=buffer state/mapping pending=] with a {{Promise}} typed {{GPUBuffer/[[mapping]]}}.
</div>

{{GPUBuffer}} is {{Serializable}}. It is a reference to an internal buffer
object, and {{Serializable}} means that the reference can be *copied* between
realms (threads/workers), allowing multiple realms to access it concurrently.
Since {{GPUBuffer}} has internal state (mapped, destroyed), that state is
internally-synchronized - these state changes occur atomically across realms.

## Buffer Creation ## {#buffer-creation}

### {{GPUBufferDescriptor}} ### {#GPUBufferDescriptor}

This specifies the options to use in creating a {{GPUBuffer}}.

<script type=idl>
dictionary GPUBufferDescriptor : GPUObjectDescriptorBase {
    required GPUSize64 size;
    required GPUBufferUsageFlags usage;
    boolean mappedAtCreation = false;
};
</script>

<div algorithm>
    <dfn abstract-op>validating GPUBufferDescriptor</dfn>(device, descriptor)
        1. If device is lost return false.
        1. If any of the bits of |descriptor|'s {{GPUBufferDescriptor/usage}} aren't present in this device's [[allowed buffer usages]] return false.
        1. If both the {{GPUBufferUsage/MAP_READ}} and {{GPUBufferUsage/MAP_WRITE}} bits of |descriptor|'s {{GPUBufferDescriptor/usage}} attribute are set, return false.
        1. Return true.
</div>

## Buffer Usage ## {#buffer-usage}

<script type=idl>
typedef [EnforceRange] unsigned long GPUBufferUsageFlags;
interface GPUBufferUsage {
    const GPUBufferUsageFlags MAP_READ      = 0x0001;
    const GPUBufferUsageFlags MAP_WRITE     = 0x0002;
    const GPUBufferUsageFlags COPY_SRC      = 0x0004;
    const GPUBufferUsageFlags COPY_DST      = 0x0008;
    const GPUBufferUsageFlags INDEX         = 0x0010;
    const GPUBufferUsageFlags VERTEX        = 0x0020;
    const GPUBufferUsageFlags UNIFORM       = 0x0040;
    const GPUBufferUsageFlags STORAGE       = 0x0080;
    const GPUBufferUsageFlags INDIRECT      = 0x0100;
    const GPUBufferUsageFlags QUERY_RESOLVE = 0x0200;
};
</script>

<dl dfn-type=method dfn-for=GPUDevice>
    : <dfn>createBuffer(descriptor)</dfn>
    ::

    <div algorithm=GPUDevice.createBuffer>
        **Called on:** {{GPUDevice}} |this|.

        **Arguments:**
        <pre class=argumentdef for="GPUDevice/createBuffer(descriptor)">
            |descriptor|:
        </pre>

        **Returns:** {{GPUBuffer}}

        1. If any of the following conditions are unsatisfied, return an error buffer and stop.
            <div class=validusage>
                - |this| is a [=valid=] {{GPUDevice}}.
                - |descriptor|.{{GPUBufferDescriptor/usage}} is a subset of |this|.[[allowed buffer usages]].
                - If |descriptor|.{{GPUBufferDescriptor/usage}} contains {{GPUBufferUsage/MAP_READ}}:
                    - |descriptor|.{{GPUBufferDescriptor/usage}} contains no other [=usage flags=]
                        except {{GPUBufferUsage/COPY_DST}}.
                - If |descriptor|.{{GPUBufferDescriptor/usage}} contains {{GPUBufferUsage/MAP_WRITE}}:
                    - |descriptor|.{{GPUBufferDescriptor/usage}} contains no other [=usage flags=]
                        except {{GPUBufferUsage/COPY_SRC}}.
                - If |descriptor|.{{GPUBufferDescriptor/mappedAtCreation}} is `true`:
                    - |descriptor|.{{GPUBufferDescriptor/size}} is a multiple of 4.

                Issue(gpuweb/gpuweb#605): Explain that the resulting error buffer can still be mapped at creation.

                Issue(gpuweb/gpuweb#605): Explain what are a {{GPUDevice}}'s `[[allowed buffer usages]]`.
            </div>

        1. Let |b| be a new {{GPUBuffer}} object.
        1. Set |b|.{{GPUBuffer/[[size]]}} to |descriptor|.{{GPUBufferDescriptor/size}}.
        1. Set |b|.{{GPUBuffer/[[usage]]}} to |descriptor|.{{GPUBufferDescriptor/usage}}.
        1. If |descriptor|.{{GPUBufferDescriptor/mappedAtCreation}} is `true`:

            1. Set |b|.{{GPUBuffer/[[mapping]]}} to a new {{ArrayBuffer}} of size |b|.{{GPUBuffer/[[size]]}}.
            1. Set |b|.{{GPUBuffer/[[mapping_range]]}} to `[0, descriptor.size]`.
            1. Set |b|.{{GPUBuffer/[[mapped_ranges]]}} to `[]`.
            1. Set |b|.{{GPUBuffer/[[state]]}} to [=buffer state/mapped at creation=].

            Else:

            1. Set |b|.{{GPUBuffer/[[mapping]]}} to `null`.
            1. Set |b|.{{GPUBuffer/[[mapping_range]]}} to `null`.
            1. Set |b|.{{GPUBuffer/[[mapped_ranges]]}} to `null`.
            1. Set |b|.{{GPUBuffer/[[state]]}} to [=buffer state/unmapped=].

        1. Set each byte of |b|'s allocation to zero.
        1. Return |b|.

        Note: it is valid to set {{GPUBufferDescriptor/mappedAtCreation}} to true without {{GPUBufferUsage/MAP_READ}}
        or {{GPUBufferUsage/MAP_WRITE}} in {{GPUBufferDescriptor/usage}}. This can be used to set the buffer's
        initial data.

    </div>

</dl>

## Buffer Destruction ## {#buffer-destruction}

An application that no longer requires a {{GPUBuffer}} can choose to lose
access to it before garbage collection by calling {{GPUBuffer/destroy()}}.

Note: This allows the user agent to reclaim the GPU memory associated with the {{GPUBuffer}}
once all previously submitted operations using it are complete.

<dl dfn-type=method dfn-for=GPUBuffer>
    : <dfn>destroy()</dfn>
    ::

    <div algorithm=GPUBuffer.destroy>
        **Called on:** {{GPUBuffer}} |this|.

        **Returns:** void

        1. If the |this|.{{GPUBuffer/[[state]]}} is [=buffer state/mapped=] or [=buffer state/mapped at creation=]:
            1. Run the steps to unmap |this|.

        1. Set |this|.{{GPUBuffer/[[state]]}} to [=buffer state/destroyed=].

        Issue: Handle error buffers once we have a description of the error monad.
    </div>
</dl>

## Buffer Mapping ## {#buffer-mapping}

An application can request to map a {{GPUBuffer}} so that they can access its
content via {{ArrayBuffer}}s that represent part of the {{GPUBuffer}}'s
allocations. Mapping a {{GPUBuffer}} is requested asynchronously with
{{GPUBuffer/mapAsync()}} so that the user agent can ensure the GPU
finished using the {{GPUBuffer}} before the application can access its content.
Once the {{GPUBuffer}} is mapped the application can synchronously ask for access
to ranges of its content with {{GPUBuffer/getMappedRange}}. A mapped {{GPUBuffer}}
cannot be used by the GPU and must be unmapped using {{GPUBuffer/unmap}} before
work using it can be submitted to the [=Queue timeline=].

Issue(gpuweb/gpuweb#605): Add client-side validation that a mapped buffer can
  only be unmapped and destroyed on the worker on which it was mapped. Likewise
  {{GPUBuffer/getMappedRange}} can only be called on that worker.

<script type=idl>
typedef [EnforceRange] unsigned long GPUMapModeFlags;
interface GPUMapMode {
    const GPUMapModeFlags READ  = 0x0001;
    const GPUMapModeFlags WRITE = 0x0002;
};
</script>

<dl dfn-type=method dfn-for=GPUBuffer>
    : <dfn>mapAsync(mode, offset, size)</dfn>
    ::

        <div algorithm=GPUBuffer.mapAsync>
            **Called on:** {{GPUBuffer}} |this|.

            **Arguments:**
            <pre class=argumentdef for="GPUBuffer/mapAsync(mode, offset, size)">
                |mode|:
                |offset|:
                |size|:
            </pre>

            **Returns:** `Promise<void>`

            Issue(gpuweb/gpuweb#605): Handle error buffers once we have a description of the error monad.

            1. If |size| is unspecified:
                1. If |offset| &gt; |this|.{{GPUBuffer/[[size]]}}, reject with an {{OperationError}} and stop.
                1. Let |rangeSize| be |this|.{{GPUBuffer/[[size]]}} - |offset|.

                Otherwise, let |rangeSize| be |size|.

            1. If any of the following conditions are unsatisfied:
                <div class=validusage>
                    - |this| is a [=valid=] {{GPUBuffer}}.
                    - |offset| is a multiple of 4.
                    - |rangeSize| is a multiple of 4.
                    - |offset| + |rangeSize| is less or equal to |this|.{{GPUBuffer/[[size]]}}
                    - |this|.{{GPUBuffer/[[state]]}} is [=buffer state/unmapped=]
                    - |mode| contains exactly one of {{GPUMapMode/READ}} or {{GPUMapMode/WRITE}}.
                    - If |mode| contains {{GPUMapMode/READ}} then |this|.{{GPUBuffer/[[usage]]}} must contain {{GPUBufferUsage/MAP_READ}}.
                    - If |mode| contains {{GPUMapMode/WRITE}} then |this|.{{GPUBuffer/[[usage]]}} must contain {{GPUBufferUsage/MAP_WRITE}}.

                    Issue: Do we validate that |mode| contains only valid flags?
                </div>

                Then:
                1. Record a validation error on the current scope.
                1. Return [=a promise rejected with=] an {{AbortError}} on the [=Device timeline=].

            1. Let |p| be a new {{Promise}}.
            1. Set |this|.{{GPUBuffer/[[mapping]]}} to |p|.
            1. Set |this|.{{GPUBuffer/[[state]]}} to [=buffer state/mapping pending=].
            1. Set |this|.{{GPUBuffer/[[map_mode]]}} to |mode|.
            1. Enqueue an operation on the default queue's [=Queue timeline=] that will execute the following:
                <div class=queue-timeline>
                    1. If |this|.{{GPUBuffer/[[state]]}} is [=buffer state/mapping pending=]:

                        1. Let |m| be a new {{ArrayBuffer}} of size |rangeSize|.
                        1. Set the content of |m| to the content of |this|'s allocation starting at offset |offset| and for |rangeSize| bytes.
                        1. Set |this|.{{GPUBuffer/[[mapping]]}} to |m|.
                        1. Set |this|.{{GPUBuffer/[[state]]}} to [=buffer state/mapped=].
                        1. Set |this|.{{GPUBuffer/[[mapping_range]]}} to <code>[|offset|, |offset| + |rangeSize|]</code>.
                        1. Set |this|.{{GPUBuffer/[[mapped_ranges]]}} to `[]`.

                    1. Resolve |p|.
                </div>
            1. Return |p|.
        </div>

    : <dfn>getMappedRange(offset, size)</dfn>
    ::

        <div algorithm=GPUBuffer.getMappedRange>
            **Called on:** {{GPUBuffer}} |this|.

            **Arguments:**
            <pre class=argumentdef for="GPUBuffer/getMappedRange(offset, size)">
                |offset|:
                |size|:
            </pre>

            **Returns:** {{ArrayBuffer}}

            1. If |size| is unspecified:
                1. If |offset| &gt; this.{{GPUBuffer/[[size]]}}, throw an {{OperationError}} and stop.
                1. Let |rangeSize| be this.{{GPUBuffer/[[size]]}} - |offset|.

                Else:
                1. Let |rangeSize| be |size|.

            1. If any of the following conditions are unsatisfied, throw an {{OperationError}} and stop.
                <div class=validusage>
                    - |this|.{{GPUBuffer/[[state]]}} is [=buffer state/mapped=] or [=buffer state/mapped at creation=].
                    - |offset| is a multiple of 8.
                    - |rangeSize| is a multiple of 4.
                    - |offset| is greater than or equal to |this|.{{GPUBuffer/[[mapping_range]]}}[0].
                    - |offset| + |rangeSize| is less than or equal to |this|.{{GPUBuffer/[[mapping_range]]}}[1].
                    - [|offset|, |offset| + |rangeSize|) does not overlap another range in |this|.{{GPUBuffer/[[mapped_ranges]]}}.

                    Note: It is always valid to get mapped ranges of a {{GPUBuffer}} that is
                    [=buffer state/mapped at creation=], even if it is [=invalid=], because
                    the [=Content timeline=] might not know it is invalid.

                    Issue: Consider aligning mapAsync offset to 8 to match this.
                </div>

            1. Let |m| be a new {{ArrayBuffer}} of size |rangeSize| pointing at the content
                of |this|.{{GPUBuffer/[[mapping]]}} at offset |offset| - |this|.{{GPUBuffer/[[mapping_range]]}}[0].

            1. Append |m| to |this|.{{GPUBuffer/[[mapped_ranges]]}}.

            1. Return |m|.
        </div>

    : <dfn>unmap()</dfn>
    ::

        <div algorithm=GPUBuffer.unmap>
            **Called on:** {{GPUBuffer}} |this|.

            **Returns:** void

            1. If any of the following conditions are unsatisfied, generate a validation
                error and stop.
                <div class=validusage>
                    - |this|.{{GPUBuffer/[[state]]}} is not [=buffer state/unmapped=]
                    - |this|.{{GPUBuffer/[[state]]}} is not [=buffer state/destroyed=]

                    Note: It is valid to unmap an error {{GPUBuffer}} that is
                        [=buffer state/mapped at creation=] because the [=Content timeline=]
                        might not know it is an error {{GPUBuffer}}.
                </div>

            1. If |this|.{{GPUBuffer/[[state]]}} is [=buffer state/mapping pending=]:

                1. [=Reject=] {{GPUBuffer/[[mapping]]}} with an {{OperationError}}.
                1. Set |this|.{{GPUBuffer/[[mapping]]}} to null.

            1. If |this|.{{GPUBuffer/[[state]]}} is [=buffer state/mapped=] or [=buffer state/mapped at creation=]:

                1. If one of the two following conditions holds:

                    - |this|.{{GPUBuffer/[[state]]}} is [=buffer state/mapped at creation=]
                    - |this|.{{GPUBuffer/[[state]]}} is [=buffer state/mapped=] and |this|.{{GPUBuffer/[[map_mode]]}} contains {{GPUMapMode/WRITE}}

                    Then:
                    1. Enqueue an operation on the default queue's [=Queue timeline=] that updates the |this|.{{GPUBuffer/[[mapping_range]]}}
                        of |this|'s allocation to the content of |this|.{{GPUBuffer/[[mapping]]}}.

                1. Detach each {{ArrayBuffer}} in |this|.{{GPUBuffer/[[mapped_ranges]]}} from its content.
                1. Set |this|.{{GPUBuffer/[[mapping]]}} to null.
                1. Set |this|.{{GPUBuffer/[[mapping_range]]}} to null.
                1. Set |this|.{{GPUBuffer/[[mapped_ranges]]}} to null.

            1. Set |this|.{{GPUBuffer/[[state]]}} to [=buffer state/unmapped=].

            Note: When a {{GPUBufferUsage/MAP_READ}} buffer (not currently mapped at creation) is
                unmapped, any local modifications done by the application to the mapped ranges
                {{ArrayBuffer}} are discarded and will not affect the content of follow-up mappings.
        </div>
</dl>

# Textures and Texture Views # {#textures}

Issue: define <dfn dfn>texture</dfn> (internal object)

Issue: define <dfn dfn>mipmap level</dfn>, <dfn dfn>array layer</dfn>, <dfn dfn>slice</dfn> (concepts)

## <dfn interface>GPUTexture</dfn> ## {#texture-interface}

<script type=idl>
[Serializable]
interface GPUTexture {
    GPUTextureView createView(optional GPUTextureViewDescriptor descriptor = {});

    void destroy();
};
GPUTexture includes GPUObjectBase;
</script>

{{GPUTexture}} has the following internal slots:
<dl dfn-type=attribute dfn-for="GPUTexture">
    : <dfn>\[[textureSize]]</dfn> of type {{GPUExtent3D}}.
    ::
        The size of the {{GPUTexture}} in texels in [=mipmap level=] 0.

    : <dfn>\[[mipLevelCount]]</dfn> of type {{GPUIntegerCoordinate}}.
    ::
        The total number of the mipmap levels of the {{GPUTexture}}.

    : <dfn>\[[sampleCount]]</dfn> of type {{GPUSize32}}.
    ::
        The number of samples in each texel of the {{GPUTexture}}.

    : <dfn>\[[dimension]]</dfn> of type {{GPUTextureDimension}}.
    ::
        The dimension of the {{GPUTexture}}.

    : <dfn>\[[format]]</dfn> of type {{GPUTextureFormat}}.
    ::
        The format of the {{GPUTexture}}.

    : <dfn>\[[textureUsage]]</dfn> of type {{GPUTextureUsageFlags}}.
    ::
        The allowed usages for this {{GPUTexture}}.

</dl>

### Texture Creation ### {#texture-creation}

<script type=idl>
dictionary GPUTextureDescriptor : GPUObjectDescriptorBase {
    required GPUExtent3D size;
    GPUIntegerCoordinate mipLevelCount = 1;
    GPUSize32 sampleCount = 1;
    GPUTextureDimension dimension = "2d";
    required GPUTextureFormat format;
    required GPUTextureUsageFlags usage;
};
</script>

<script type=idl>
enum GPUTextureDimension {
    "1d",
    "2d",
    "3d"
};
</script>

<script type=idl>
typedef [EnforceRange] unsigned long GPUTextureUsageFlags;
interface GPUTextureUsage {
    const GPUTextureUsageFlags COPY_SRC          = 0x01;
    const GPUTextureUsageFlags COPY_DST          = 0x02;
    const GPUTextureUsageFlags SAMPLED           = 0x04;
    const GPUTextureUsageFlags STORAGE           = 0x08;
    const GPUTextureUsageFlags OUTPUT_ATTACHMENT = 0x10;
};
</script>

<dl dfn-type=method dfn-for=GPUDevice>
    : <dfn>createTexture(descriptor)</dfn>
    ::
        Creates a new {{GPUTexture}}.

        <div algorithm=GPUDevice.createTexture>
            **Called on:** {{GPUDevice}} this.

            **Arguments:**
            <pre class=argumentdef for="GPUDevice/createTexture(descriptor)">
                descriptor:
            </pre>

            **Returns:** {{GPUTexture}}

            Issue: Describe {{GPUDevice/createTexture()}} algorithm steps.
        </div>
</dl>

### Texture Destruction ### {#texture-destruction}

An application that no longer requires a {{GPUTexture}} can choose to lose access to it before
garbage collection by calling {{GPUTexture/destroy()}}.

Note: This allows the user agent to reclaim the GPU memory associated with the {{GPUTexture}} once
all previously submitted operations using it are complete.

<dl dfn-type=method dfn-for=GPUTexture>
    : <dfn>destroy()</dfn>
    ::
        Destroys a {{GPUTexture}}.

        <div algorithm=GPUTexture.destroy>
            **Called on:** {{GPUTexture}} this.

            **Returns:** void

            Issue: Describe {{GPUTexture/destroy()}} algorithm steps.
        </div>
</dl>

## GPUTextureView ## {#gpu-textureview}

<script type=idl>
interface GPUTextureView {
};
GPUTextureView includes GPUObjectBase;
</script>

{{GPUTextureView}} has the following internal slots:

<dl dfn-type=attribute dfn-for="GPUTextureView">
    : <dfn>\[[texture]]</dfn>
    ::
        The {{GPUTexture}} into which this is a view.

    : <dfn>\[[descriptor]]</dfn>
    ::
        The {{GPUTextureViewDescriptor}} describing this texture view.

        All optional fields of {{GPUTextureViewDescriptor}} are defined.
</dl>

### Texture View Creation ### {#texture-view-creation}

<script type=idl>
dictionary GPUTextureViewDescriptor : GPUObjectDescriptorBase {
    GPUTextureFormat format;
    GPUTextureViewDimension dimension;
    GPUTextureAspect aspect = "all";
    GPUIntegerCoordinate baseMipLevel = 0;
    GPUIntegerCoordinate mipLevelCount;
    GPUIntegerCoordinate baseArrayLayer = 0;
    GPUIntegerCoordinate arrayLayerCount;
};
</script>

Issue: Make this a standalone algorithm used in the createView algorithm.

Issue: The references to GPUTextureDescriptor here should actually refer to
internal slots of a [=texture=] internal object once we have one.

<div algorithm="resolving GPUTextureViewDescriptor defaults">

  * {{GPUTextureViewDescriptor/format}}:
    If unspecified, defaults to |texture|.{{GPUTextureDescriptor/format}}.

  * {{GPUTextureViewDescriptor/dimension}}:
    If unspecified:
      - If |texture|.{{GPUTextureDescriptor/dimension}} is {{GPUTextureDimension/"1d"}},
        defaults to {{GPUTextureViewDimension/"1d"}}.
      - If |texture|.{{GPUTextureDescriptor/dimension}} is {{GPUTextureDimension/"2d"}}:
          - If |texture|.{{GPUTextureDescriptor/size}}.[=Extent3D/depth=] is greater than 1
            and {{GPUTextureViewDescriptor/arrayLayerCount}} is 0,
            defaults to {{GPUTextureViewDimension/"2d-array"}}.
          - Otherwise, defaults to {{GPUTextureViewDimension/"2d"}}.
      - If |texture|.{{GPUTextureDescriptor/dimension}} is {{GPUTextureDimension/"3d"}},
        defaults to {{GPUTextureViewDimension/"3d"}}.

  * {{GPUTextureViewDescriptor/mipLevelCount}}:
    If undefined, defaults to |texture|.{{GPUTextureDescriptor/mipLevelCount}} &minus; {{GPUTextureViewDescriptor/baseMipLevel}}.

  * {{GPUTextureViewDescriptor/arrayLayerCount}}:
    If undefined, defaults to |texture|.{{GPUTextureDescriptor/size}}.[=Extent3D/depth=] &minus; {{GPUTextureViewDescriptor/baseArrayLayer}}.

</div>

<script type=idl>
enum GPUTextureViewDimension {
    "1d",
    "2d",
    "2d-array",
    "cube",
    "cube-array",
    "3d"
};
</script>

<script type=idl>
enum GPUTextureAspect {
    "all",
    "stencil-only",
    "depth-only"
};
</script>

### {{GPUTexture}}.<dfn method for=GPUTexture>createView(descriptor)</dfn> ### {#textureview-createview}

<div algorithm=GPUTexture.createView>
    <strong>|this|:</strong> of type {{GPUTexture}}.

    **Arguments:**
        - optional {{GPUTextureViewDescriptor}} |descriptor|

    **Returns:** |view|, of type {{GPUTextureView}}.

    Issue: write definition. |this| |descriptor| |view|
</div>

## Texture Formats ## {#texture-formats}

The name of the format specifies the order of components, bits per component,
and data type for the component.

  * `r`, `g`, `b`, `a` = red, green, blue, alpha
  * `unorm` = unsigned normalized
  * `snorm` = signed normalized
  * `uint` = unsigned int
  * `sint` = signed int
  * `float` = floating point

If the format has the `-srgb` suffix, then sRGB conversions from gamma to linear
and vice versa are applied during the reading and writing of color values in the
shader. Compressed texture formats are provided by extensions. Their naming
should follow the convention here, with the texture name as a prefix. e.g.
`etc2-rgba8unorm`.

The <dfn dfn>texel block</dfn> is a single addressable element of the textures in pixel-based {{GPUTextureFormat}}s,
and a single compressed block of the textures in block-based compressed {{GPUTextureFormat}}s.

The <dfn dfn>texel block width</dfn> and <dfn dfn>texel block height</dfn> specifies the dimension of one [=texel block=].
  - For pixel-based {{GPUTextureFormat}}s, the [=texel block width=] and [=texel block height=] are always 1.
  - For block-based compressed {{GPUTextureFormat}}s, the [=texel block width=] is the number of texels in each row of one [=texel block=],
    and the [=texel block height=] is the number of texel rows in one [=texel block=].

The <dfn dfn>texel block size</dfn> of a {{GPUTextureFormat}} is the number of bytes to store one [=texel block=].
The [=texel block size=] of each {{GPUTextureFormat}} is constant except for {{GPUTextureFormat/"depth24plus"}} and
{{GPUTextureFormat/"depth24plus-stencil8"}}.

<script type=idl>
enum GPUTextureFormat {
    // 8-bit formats
    "r8unorm",
    "r8snorm",
    "r8uint",
    "r8sint",

    // 16-bit formats
    "r16uint",
    "r16sint",
    "r16float",
    "rg8unorm",
    "rg8snorm",
    "rg8uint",
    "rg8sint",

    // 32-bit formats
    "r32uint",
    "r32sint",
    "r32float",
    "rg16uint",
    "rg16sint",
    "rg16float",
    "rgba8unorm",
    "rgba8unorm-srgb",
    "rgba8snorm",
    "rgba8uint",
    "rgba8sint",
    "bgra8unorm",
    "bgra8unorm-srgb",
    // Packed 32-bit formats
    "rgb10a2unorm",
    "rg11b10float",

    // 64-bit formats
    "rg32uint",
    "rg32sint",
    "rg32float",
    "rgba16uint",
    "rgba16sint",
    "rgba16float",

    // 128-bit formats
    "rgba32uint",
    "rgba32sint",
    "rgba32float",

    // Depth and stencil formats
    "depth32float",
    "depth24plus",
    "depth24plus-stencil8",

    // BC compressed formats usable if "texture-compression-bc" is both
    // supported by the device/user agent and enabled in requestDevice.
    "bc1-rgba-unorm",
    "bc1-rgba-unorm-srgb",
    "bc2-rgba-unorm",
    "bc2-rgba-unorm-srgb",
    "bc3-rgba-unorm",
    "bc3-rgba-unorm-srgb",
    "bc4-r-unorm",
    "bc4-r-snorm",
    "bc5-rg-unorm",
    "bc5-rg-snorm",
    "bc6h-rgb-ufloat",
    "bc6h-rgb-sfloat",
    "bc7-rgba-unorm",
    "bc7-rgba-unorm-srgb"
};
</script>

The depth aspect of the `depth24plus` family of formats
({{GPUTextureFormat/depth24plus}} and {{GPUTextureFormat/depth24plus-stencil8}})
may be implemented as either a 24-bit unsigned normalized value ("depth24unorm")
or a 32-bit IEEE 754 floating point value ("depth32float").

Note:
While the precision of depth32float is strictly higher than the precision of
depth24unorm for all values in the representable range (0.0 to 1.0),
note that the set of representable values is not exactly the same:
for depth24unorm, 1 ULP has a constant value of 1 / (2<sup>24</sup> &minus; 1);
for depth32float, 1 ULP has a variable value no greater than 1 / (2<sup>24</sup>).

<script type=idl>
enum GPUTextureComponentType {
    "float",
    "sint",
    "uint"
};
</script>


# Samplers # {#samplers}

## <dfn interface>GPUSampler</dfn> ## {#sampler-interface}

A {{GPUSampler}} encodes transformations and filtering information that can
be used in a shader to interpret texture resource data.

{{GPUSampler|GPUSamplers}} are created via {{GPUDevice/createSampler(descriptor)|GPUDevice.createSampler(optional descriptor)}}
that returns a new sampler object.

<script type=idl>
interface GPUSampler {
};
GPUSampler includes GPUObjectBase;
</script>

{{GPUSampler}} has the following internal slots:

<dl dfn-type=attribute dfn-for="GPUSampler">
    : <dfn>\[[descriptor]]</dfn>, of type {{GPUSamplerDescriptor}}, readonly
    ::
        The {{GPUSamplerDescriptor}} with which the {{GPUSampler}} was created.
    : <dfn>\[[compareEnable]]</dfn> of type {{boolean}}.
    ::
        Whether the {{GPUSampler}} is used as a comparison sampler.
</dl>

## Sampler Creation ## {#sampler-creation}

### {{GPUSamplerDescriptor}} ### {#GPUSamplerDescriptor}

A {{GPUSamplerDescriptor}} specifies the options to use to create a {{GPUSampler}}.

<script type=idl>
dictionary GPUSamplerDescriptor : GPUObjectDescriptorBase {
    GPUAddressMode addressModeU = "clamp-to-edge";
    GPUAddressMode addressModeV = "clamp-to-edge";
    GPUAddressMode addressModeW = "clamp-to-edge";
    GPUFilterMode magFilter = "nearest";
    GPUFilterMode minFilter = "nearest";
    GPUFilterMode mipmapFilter = "nearest";
    float lodMinClamp = 0;
    float lodMaxClamp = 0xffffffff; // TODO: What should this be? Was Number.MAX_VALUE.
    GPUCompareFunction compare;
    unsigned short maxAnisotropy = 1;
};
</script>

- {{GPUSamplerDescriptor/addressModeU}}, {{GPUSamplerDescriptor/addressModeV}},
    and {{GPUSamplerDescriptor/addressModeW}} specify the address modes for the texture width,
    height, and depth coordinates, respectively.
- {{GPUSamplerDescriptor/magFilter}} specifies the sampling behavior when the sample footprint
    is smaller than or equal to one texel.
- {{GPUSamplerDescriptor/minFilter}} specifies the sampling behavior when the sample footprint
    is larger than one texel.
- {{GPUSamplerDescriptor/mipmapFilter}} specifies behavior for sampling between two mipmap levels.
- {{GPUSamplerDescriptor/lodMinClamp}} and {{GPUSamplerDescriptor/lodMaxClamp}} specify the minimum and
    maximum levels of detail, respectively, used internally when sampling a texture.
- If {{GPUSamplerDescriptor/compare}} is provided, the sampler will be a comparison sampler with the specified
    {{GPUCompareFunction}}.
- {{GPUSamplerDescriptor/maxAnisotropy}} specifies the maximum anisotropy value clamp used by the sampler.

    Note: most implementations support {{GPUSamplerDescriptor/maxAnisotropy}} values in range between 1 and 16, inclusive.

Issue: explain how LOD is calculated and if there are differences here between platforms.
Issue: explain what anisotropic sampling is

{{GPUAddressMode}} describes the behavior of the sampler if the sample footprint extends beyond
the bounds of the sampled texture.

Issue: Describe a "sample footprint" in greater detail.

<script type=idl>
enum GPUAddressMode {
    "clamp-to-edge",
    "repeat",
    "mirror-repeat"
};
</script>

<dl dfn-type="enum-value" dfn-for=GPUAddressMode>
    : <dfn>"clamp-to-edge"</dfn>
    ::
        Texture coordinates are clamped between 0.0 and 1.0, inclusive.

    : <dfn>"repeat"</dfn>
    ::
        Texture coordinates wrap to the other side of the texture.

    : <dfn>"mirror-repeat"</dfn>
    ::
        Texture coordinates wrap to the other side of the texture, but the texture is flipped
        when the integer part of the coordinate is odd.
</dl>

{{GPUFilterMode}} describes the behavior of the sampler if the sample footprint does not exactly
match one texel.

<script type=idl>
enum GPUFilterMode {
    "nearest",
    "linear"
};
</script>

<dl dfn-type="enum-value" dfn-for=GPUFilterMode>
    : <dfn>"nearest"</dfn>
    ::
        Return the value of the texel nearest to the texture coordinates.

    : <dfn>"linear"</dfn>
    ::
        Select two texels in each dimension and return a linear interpolation between their values.
</dl>

{{GPUCompareFunction}} specifies the behavior of a comparison sampler. If a comparison sampler is
used in a shader, an input value is compared to the sampled texture value, and the result of this
comparison test (0.0f for pass, or 1.0f for fail) is used in the filtering operation.

Issue: describe how filtering interacts with comparison sampling.

<script type=idl>
enum GPUCompareFunction {
    "never",
    "less",
    "equal",
    "less-equal",
    "greater",
    "not-equal",
    "greater-equal",
    "always"
};
</script>

<dl dfn-type="enum-value" dfn-for=GPUCompareFunction>
    : <dfn>"never"</dfn>
    ::
        Comparison tests never pass.

    : <dfn>"less"</dfn>
    ::
        A provided value passes the comparison test if it is less than the sampled value.

    : <dfn>"equal"</dfn>
    ::
        A provided value passes the comparison test if it is equal to the sampled value.

    : <dfn>"less-equal"</dfn>
    ::
        A provided value passes the comparison test if it is less than or equal to the sampled value.

    : <dfn>"greater"</dfn>
    ::
        A provided value passes the comparison test if it is greater than the sampled value.

    : <dfn>"not-equal"</dfn>
    ::
        A provided value passes the comparison test if it is not equal to the sampled value.

    : <dfn>"greater-equal"</dfn>
    ::
        A provided value passes the comparison test if it is greater than or equal to the sampled value.

    : <dfn>"always"</dfn>
    ::
        Comparison tests always pass.
</dl>

<div algorithm>
    <dfn abstract-op>validating GPUSamplerDescriptor</dfn>(device, descriptor)
    **Arguments:**
        - {{GPUDevice}} |device|
        - {{GPUSamplerDescriptor}} |descriptor|

    **Returns:** boolean

    Return true if and only if all of the following conditions apply:
        - |device| is valid.
        - |descriptor|.{{GPUSamplerDescriptor/lodMinClamp}} is greater than or equal to 0.
        - |descriptor|.{{GPUSamplerDescriptor/lodMaxClamp}} is greater than or equal to
            |descriptor|.{{GPUSamplerDescriptor/lodMinClamp}}.
</div>

### {{GPUDevice}}.<dfn method for=GPUDevice>createSampler(descriptor)</dfn> ### {#sampler-createsampler}

<div algorithm=GPUDevice.createSampler>
    **Arguments:**
        - optional {{GPUSamplerDescriptor}} |descriptor| = {}

    **Returns:** {{GPUSampler}}

    1. Let |s| be a new {{GPUSampler}} object.
    1. Set |s|.{{GPUSampler/[[descriptor]]}} to |descriptor|.
    1. Set |s|.{{GPUSampler/[[compareEnable]]}} to false if the {{GPUSamplerDescriptor/compare}} attribute
            of |s|.{{GPUSampler/[[descriptor]]}} is null or undefined. Otherwise, set it to true.
    1. Return |s|.

    <div class=validusage dfn-for=GPUDevice.createSampler>
        <dfn abstract-op>Valid Usage</dfn>
        - If |descriptor| is not null or undefined:
            - If [$validating GPUSamplerDescriptor$](this, |descriptor|) returns false:
                1. Generate a {{GPUValidationError}} in the current scope with appropriate error message.
                1. Create a new [=invalid=] {{GPUSampler}} and return the result.
    </div>
</div>

# Resource Binding # {#bindings}

## GPUBindGroupLayout ## {#bind-group-layout}

A {{GPUBindGroupLayout}} defines the interface between a set of resources bound in a {{GPUBindGroup}} and their accessibility in shader stages.

<script type=idl>
[Serializable]
interface GPUBindGroupLayout {
};
GPUBindGroupLayout includes GPUObjectBase;
</script>

### Creation ### {#bind-group-layout-creation}

A {{GPUBindGroupLayout}} is created via {{GPUDevice/createBindGroupLayout()|GPUDevice.createBindGroupLayout()}}.

<script type=idl>
dictionary GPUBindGroupLayoutDescriptor : GPUObjectDescriptorBase {
    required sequence<GPUBindGroupLayoutEntry> entries;
};
</script>

A {{GPUBindGroupLayoutEntry}} describes a single shader resource binding to be included in a {{GPUBindGroupLayout}}.

<script type=idl>
dictionary GPUBindGroupLayoutEntry {
    required GPUIndex32 binding;
    required GPUShaderStageFlags visibility;
    required GPUBindingType type;

    // Used for uniform buffer and storage buffer bindings. Must be undefined for other binding types.
    boolean hasDynamicOffset;

    // Used for uniform buffer and storage buffer bindings. Must be undefined for other binding types.
    GPUSize64 minBufferBindingSize;

    // Used for sampled texture and storage texture bindings. Must be undefined for other binding types.
    GPUTextureViewDimension viewDimension;

    // Used for sampled texture bindings. Must be undefined for other binding types.
    GPUTextureComponentType textureComponentType;
    boolean multisampled;

    // Used for storage texture bindings. Must be undefined for other binding types.
    GPUTextureFormat storageTextureFormat;
};
</script>

Issue(https://github.com/gpuweb/gpuweb/issues/851): consider making `textureComponentType` and `storageTextureFormat` truly optional.

<dl dfn-type=dict-member dfn-for=GPUBindGroupLayoutEntry>
    : <dfn>binding</dfn>
    ::
        A unique identifier for a resource binding within a
        {{GPUBindGroupLayoutEntry}}, a corresponding {{GPUBindGroupEntry}},
        and the {{GPUShaderModule}}s.

    : <dfn>visibility</dfn>
    ::
        A bitset of the members of {{GPUShaderStage}}.
        Each set bit indicates that a {{GPUBindGroupLayoutEntry}}'s resource
        will be accessible from the associated shader stage.

    : <dfn>type</dfn>
    ::
        The type of the binding.
        The value of this member influences the interpretation of other members.

        Note:
        This member is used to determine compatibility between a
        {{GPUPipelineLayout}} and a {{GPUShaderModule}}.

    : <dfn>hasDynamicOffset</dfn>
    ::
        If the {{GPUBindGroupLayoutEntry/type}} is
        {{GPUBindingType/"uniform-buffer"}},
        {{GPUBindingType/"storage-buffer"}}, or
        {{GPUBindingType/"readonly-storage-buffer"}}:

          - This indicates whether a binding requires a dynamic offset.
          - If `undefined`, it defaults to `false`.

        Otherwise, it must be `undefined`.

    : <dfn>minBufferBindingSize</dfn>
    ::
        If the {{GPUBindGroupLayoutEntry/type}} is
        {{GPUBindingType/"uniform-buffer"}},
        {{GPUBindingType/"storage-buffer"}}, or
        {{GPUBindingType/"readonly-storage-buffer"}}:

          - This may be used to indicate the minimum buffer binding size.
          - If `undefined`, it defaults to 0.

        Otherwise, it must be `undefined`.

    : <dfn>viewDimension</dfn>
    ::
        If the {{GPUBindGroupLayoutEntry/type}} is
        {{GPUBindingType/"sampled-texture"}},
        {{GPUBindingType/"readonly-storage-texture"}}, or
        {{GPUBindingType/"writeonly-storage-texture"}}:

          - This is the required {{GPUTextureViewDescriptor/dimension}}
            of a texture view bound to this binding.
          - If `undefined`, it defaults to {{GPUTextureViewDimension/"2d"}}.

        Otherwise, it must be `undefined`.

    : <dfn>textureComponentType</dfn>
    ::
        If the {{GPUBindGroupLayoutEntry/type}} is
        {{GPUBindingType/"sampled-texture"}}:

          - This is the required component type of the
            {{GPUTextureViewDescriptor/format}}
            of a texture view bound to this binding.
          - If `undefined`, it defaults to {{GPUTextureComponentType/"float"}}.

        Otherwise, it must be `undefined`.

    : <dfn>multisampled</dfn>
    ::
        If the {{GPUBindGroupLayoutEntry/type}} is
        {{GPUBindingType/"sampled-texture"}}:

          - This indicates whether a binding must have a sample count greater than 1.
          - If `undefined`, it defaults to `false`.

        Otherwise, it must be `undefined`.

        Note:
        This member is used to determine compatibility between a
        {{GPUPipelineLayout}} and a {{GPUShaderModule}}.

    : <dfn>storageTextureFormat</dfn>
    ::
        If the {{GPUBindGroupLayoutEntry/type}} is
        {{GPUBindingType/"readonly-storage-texture"}}
        or {{GPUBindingType/"writeonly-storage-texture"}},
        this is the required {{GPUTextureViewDescriptor/format}}
        of a texture view bound to this binding.

        Otherwise, it must be `undefined`.
</dl>

Note:
{{GPUBindGroupLayoutEntry/viewDimension}} and {{GPUBindGroupLayoutEntry/multisampled}}
enable Metal-based WebGPU implementations to back the respective bind groups
with `MTLArgumentBuffer` objects that are more efficient to bind at run-time.

<script type=idl>
typedef [EnforceRange] unsigned long GPUShaderStageFlags;
interface GPUShaderStage {
    const GPUShaderStageFlags VERTEX   = 0x1;
    const GPUShaderStageFlags FRAGMENT = 0x2;
    const GPUShaderStageFlags COMPUTE  = 0x4;
};
</script>

  * {{GPUBindGroupLayoutEntry/type}}:
    A member of {{GPUBindingType}} that indicates the intended usage of a resource binding in its visible {{GPUShaderStage}}s.

<script type=idl>
enum GPUBindingType {
    "uniform-buffer",
    "storage-buffer",
    "readonly-storage-buffer",
    "sampler",
    "comparison-sampler",
    "sampled-texture",
    "readonly-storage-texture",
    "writeonly-storage-texture"
};
</script>

A {{GPUBindGroupLayout}} object has the following methods:

<dl dfn-type=attribute dfn-for="GPUBindGroupLayout">
    : <dfn>\[[entryMap]]</dfn> of type map&lt;{{GPUSize32}}, {{GPUBindGroupLayoutEntry}}&gt.
    ::
        The map of binding indices pointing to the {{GPUBindGroupLayoutEntry}}s,
        which this {{GPUBindGroupLayout}} describes.

    : <dfn>\[[dynamicOffsetCount]]</dfn> of type {{GPUSize32}}.
    ::
        The number of buffer bindings with dynamic offsets in this {{GPUBindGroupLayout}}.
</dl>

<dl dfn-type=method dfn-for=GPUDevice>
    : <dfn>createBindGroupLayout(descriptor)</dfn>
    ::

        Creates a {{GPUBindGroupLayout}}.

        <div algorithm=GPUDevice.createBindGroupLayout>
            **Called on:** {{GPUDevice}} |this|.

            **Arguments:**
            <pre class=argumentdef for="GPUDevice/createBindGroupLayout(descriptor)">
                |descriptor|:
            </pre>

            **Returns:** {{GPUBindGroupLayout}}

            1. Let |layout| be a new valid {{GPUBindGroupLayout}} object.
            1. Issue the following steps on the [=Device timeline=] of |this|:
                <div class=device-timeline>
                    1. If any of the following conditions are unsatisfied:
                        <div class=validusage>
                            - |this| is a [=valid=] {{GPUDevice}}.
                            - The {{GPUBindGroupLayoutEntry/binding}} of each entry in |descriptor| is unique.
                            - For each shader stage, the number of entries in |descriptor| with
                                {{GPUBindGroupLayoutEntry/type}} {{GPUBindingType/uniform-buffer}} &le;
                                {{GPULimits/maxUniformBuffersPerShaderStage|GPULimits.maxUniformBuffersPerShaderStage}}.
                            - For each shader stage, the number of entries in |descriptor| with
                                {{GPUBindGroupLayoutEntry/type}} {{GPUBindingType/storage-buffer}} &le;
                                {{GPULimits/maxStorageBuffersPerShaderStage|GPULimits.maxStorageBuffersPerShaderStage}}.
                            - For each shader stage, the number of entries in |descriptor| with
                                {{GPUBindGroupLayoutEntry/type}} {{GPUBindingType/sampled-texture}} &le;
                                {{GPULimits/maxSampledTexturesPerShaderStage|GPULimits.maxSampledTexturesPerShaderStage}}.
                            - For each shader stage, the number of entries in |descriptor| with
                                {{GPUBindGroupLayoutEntry/type}} {{GPUBindingType/readonly-storage-texture}} or
                                {{GPUBindingType/writeonly-storage-texture}} &le;
                                {{GPULimits/maxStorageTexturesPerShaderStage|GPULimits.maxStorageTexturesPerShaderStage}}.
                            - For each shader stage, the number of entries in |descriptor| with
                                {{GPUBindGroupLayoutEntry/type}} {{GPUBindingType/sampler}} &le;
                                {{GPULimits/maxSamplersPerShaderStage|GPULimits.maxSamplersPerShaderStage}}.
                            - The number of entries in |descriptor| with {{GPUBindGroupLayoutEntry/type}}
                                {{GPUBindingType/uniform-buffer}} and {{GPUBindGroupLayoutEntry/hasDynamicOffset}} `true` &le;
                                {{GPULimits/maxDynamicUniformBuffersPerPipelineLayout|GPULimits.maxDynamicUniformBuffersPerPipelineLayout}}.
                            - The number of entries in |descriptor| with {{GPUBindGroupLayoutEntry/type}}
                                {{GPUBindingType/storage-buffer}} and {{GPUBindGroupLayoutEntry/hasDynamicOffset}} `true` &le;
                                {{GPULimits/maxDynamicStorageBuffersPerPipelineLayout|GPULimits.maxDynamicStorageBuffersPerPipelineLayout}}.

                            - For each {{GPUBindGroupLayoutEntry}} |bindingDescriptor| in |descriptor|.{{GPUBindGroupLayoutDescriptor/entries}}:
                                - If |bindingDescriptor|.{{GPUBindGroupLayoutEntry/visibility}} includes
                                    {{GPUShaderStage/VERTEX}}:
                                    - |bindingDescriptor|.{{GPUBindGroupLayoutEntry/type}} is not
                                        {{GPUBindingType/storage-buffer}} or {{GPUBindingType/writeonly-storage-texture}}.

                                - If |bindingDescriptor|.{{GPUBindGroupLayoutEntry/type}} is **not**
                                    {{GPUBindingType/"uniform-buffer"}}, {{GPUBindingType/"storage-buffer"}}, or
                                    {{GPUBindingType/"readonly-storage-buffer"}}:
                                    - |bindingDescriptor|.{{GPUBindGroupLayoutEntry/hasDynamicOffset}} is `undefined`.
                                    - |bindingDescriptor|.{{GPUBindGroupLayoutEntry/minBufferBindingSize}} is `undefined`.

                                - If |bindingDescriptor|.{{GPUBindGroupLayoutEntry/type}} is **not**
                                    {{GPUBindingType/"sampled-texture"}}, {{GPUBindingType/"readonly-storage-texture"}},
                                    or {{GPUBindingType/"writeonly-storage-texture"}}:
                                        - |bindingDescriptor|.{{GPUBindGroupLayoutEntry/viewDimension}} is `undefined`.

                                - If |bindingDescriptor|.{{GPUBindGroupLayoutEntry/type}} is **not**
                                    {{GPUBindingType/"sampled-texture"}}:
                                    - |bindingDescriptor|.{{GPUBindGroupLayoutEntry/textureComponentType}} is `undefined.`
                                    - |bindingDescriptor|.{{GPUBindGroupLayoutEntry/multisampled}} is `undefined.`

                                - If |bindingDescriptor|.{{GPUBindGroupLayoutEntry/type}} is **not**
                                    {{GPUBindingType/"readonly-storage-texture"}} or
                                    {{GPUBindingType/"writeonly-storage-texture"}}:
                                    - |bindingDescriptor|.{{GPUBindGroupLayoutEntry/storageTextureFormat}} is `undefined`.

                                - If |bindingDescriptor|.{{GPUBindGroupLayoutEntry/type}} is {{GPUBindingType/sampled-texture}}
                                    and |bindingDescriptor|.{{GPUBindGroupLayoutEntry/multisampled}} is `true`:
                                    - |bindingDescriptor|.{{GPUBindGroupLayoutEntry/viewDimension}} is
                                        {{GPUTextureViewDimension/2d}}.

                                - If |bindingDescriptor|.{{GPUBindGroupLayoutEntry/type}} is
                                    {{GPUBindingType/readonly-storage-texture}} or
                                    {{GPUBindingType/writeonly-storage-texture}}:
                                    - |bindingDescriptor|.{{GPUBindGroupLayoutEntry/viewDimension}} is not
                                        {{GPUTextureViewDimension/cube}} or {{GPUTextureViewDimension/cube-array}}.
                                    - |bindingDescriptor|.{{GPUBindGroupLayoutEntry/storageTextureFormat}} must
                                        be a format which can support storage usage.
                        </div>

                        Then:
                            1. Generate a {{GPUValidationError}} in the current scope with appropriate
                                error message.
                            1. Make |layout| [=invalid=] and return |layout|.

                    1. Set |layout|.{{GPUBindGroupLayout/[[dynamicOffsetCount]]}} to the number of
                        entries in |descriptor| where {{GPUBindGroupLayoutEntry/hasDynamicOffset}} is `true`.
                    1. For each {{GPUBindGroupLayoutEntry}} |bindingDescriptor| in
                        |descriptor|.{{GPUBindGroupLayoutDescriptor/entries}}:
                        1. Insert |bindingDescriptor| into |layout|.{{GPUBindGroupLayout/[[entryMap]]}}
                            with the key of |bindingDescriptor|.{{GPUBindGroupLayoutEntry/binding}}.

                        Issue: Add a step to bake the default values (e.g.
                            {{GPUBindGroupLayoutEntry/viewDimension}} to "2d") into the |bindingDescriptor|.
                </div>
            1. Return |layout|.

        </div>
</dl>

### Compatibility ### {#bind-group-compatibility}

<div algorithm>
Two {{GPUBindGroupLayout}} objects |a| and |b| are considered <dfn dfn>group-equivalent</dfn>
if and only if, for any binding number |binding|, one of the following is true:
    - it's missing from both |a|.{{GPUBindGroupLayout/[[entryMap]]}} and |b|.{{GPUBindGroupLayout/[[entryMap]]}}.
    - |a|.{{GPUBindGroupLayout/[[entryMap]]}}[|binding|] == |b|.{{GPUBindGroupLayout/[[entryMap]]}}[|binding|]
</div>

If bind groups layouts are [=group-equivalent=] they can be interchangeably used in all contents.

## GPUBindGroup ## {#gpu-bind-group}

A {{GPUBindGroup}} defines a set of resources to be bound together in a group
    and how the resources are used in shader stages.

<script type=idl>
interface GPUBindGroup {
};
GPUBindGroup includes GPUObjectBase;
</script>

### Bind Group Creation ### {#bind-group-creation}

A {{GPUBindGroup}} is created via {{GPUDevice/createBindGroup()|GPUDevice.createBindGroup()}}.

<script type=idl>
dictionary GPUBindGroupDescriptor : GPUObjectDescriptorBase {
    required GPUBindGroupLayout layout;
    required sequence<GPUBindGroupEntry> entries;
};
</script>

A {{GPUBindGroupEntry}} describes a single resource to be bound in a {{GPUBindGroup}}.

<script type=idl>
typedef (GPUSampler or GPUTextureView or GPUBufferBinding) GPUBindingResource;

dictionary GPUBindGroupEntry {
    required GPUIndex32 binding;
    required GPUBindingResource resource;
};
</script>

<script type=idl>
dictionary GPUBufferBinding {
    required GPUBuffer buffer;
    GPUSize64 offset = 0;
    GPUSize64 size;
};
</script>

  * {{GPUBufferBinding/size}}: If undefined, specifies the range starting at
      {{GPUBufferBinding/offset}} and ending at the end of the buffer.

A {{GPUBindGroup}} object has the following internal slots:

<dl dfn-type=attribute dfn-for="GPUBindGroup">
    : <dfn>\[[layout]]</dfn> of type {{GPUBindGroupLayout}}.
    ::
        The {{GPUBindGroupLayout}} associated with this {{GPUBindGroup}}.

    : <dfn>\[[entries]]</dfn> of type sequence<{{GPUBindGroupEntry}}>.
    ::
        The set of {{GPUBindGroupEntry}}s this {{GPUBindGroup}} describes.

    : <dfn>\[[usedBuffers]]</dfn> of type maplike<{{GPUBuffer}}, {{GPUBufferUsageFlags}}>.
    ::
        The set of buffers used by this bind group and the corresponding usage flags.

    : <dfn>\[[usedTextures]]</dfn> of type maplike<{{GPUTexture}} [=subresource=], {{GPUTextureUsageFlags}}>.
    ::
        The set of texure subresources used by this bind group. Each subresource is
        stored with the union of usage flags that apply to it.
</dl>

<dl dfn-type=method dfn-for=GPUDevice>
    : <dfn>createBindGroup(descriptor)</dfn>
    ::

        Creates a {{GPUBindGroup}}.

        <div algorithm=GPUDevice.createBindGroup>
            **Called on:** {{GPUDevice}} |this|.

            **Arguments:**
            <pre class=argumentdef for="GPUDevice/createBindGroup(descriptor)">
                |descriptor|:
            </pre>

            **Returns:** {{GPUBindGroup}}

            1. Let |bindGroup| be a new valid {{GPUBindGroup}} object.
            1. Issue the following steps on the [=Device timeline=] of |this|:
                <div class=device-timeline>
                    1. If any of the following conditions are unsatisfied:
                        <div class=validusage>
                            - |this| is a [=valid=] {{GPUDevice}}.
                            - |descriptor|.{{GPUBindGroupDescriptor/layout}} is [$valid to use with$] |this|.
                            - The number of {{GPUBindGroupLayoutDescriptor/entries}} of
                                |descriptor|.{{GPUBindGroupDescriptor/layout}} is exactly equal to
                                the number of |descriptor|.{{GPUBindGroupDescriptor/entries}}.

                            For each {{GPUBindGroupEntry}} |bindingDescriptor| in
                                |descriptor|.{{GPUBindGroupDescriptor/entries}}:
                                - Let |resource| be |bindingDescriptor|.{{GPUBindGroupEntry/resource}}.
                                - There is exactly one {{GPUBindGroupLayoutEntry}} |layoutBinding|
                                    in |descriptor|.{{GPUBindGroupDescriptor/layout}}.{{GPUBindGroupLayoutDescriptor/entries}}
                                    such that |layoutBinding|.{{GPUBindGroupLayoutEntry/binding}} equals to
                                    |bindingDescriptor|.{{GPUBindGroupEntry/binding}}.

                                - If |layoutBinding|.{{GPUBindGroupLayoutEntry/type}} is {{GPUBindingType/"sampler"}}:
                                    - |resource| is [$valid to use with$] |this|.
                                    - |resource|.{{GPUSampler/[[compareEnable]]}} is `false`.

                                - If |layoutBinding|.{{GPUBindGroupLayoutEntry/type}} is {{GPUBindingType/"comparison-sampler"}}:
                                    - |resource| is [$valid to use with$] |this|.
                                    - |resource|.{{GPUSampler/[[compareEnable]]}} is `true`.

                                -  If |layoutBinding|.{{GPUBindGroupLayoutEntry/type}} is
                                    {{GPUBindingType/"sampled-texture"}} or
                                    {{GPUBindingType/"readonly-storage-texture"}} or
                                    {{GPUBindingType/"writeonly-storage-texture"}}:
                                    - |resource| is [$valid to use with$] |this|.
                                    - |layoutBinding|.{{GPUBindGroupLayoutEntry/viewDimension}} is
                                        equal to |resource|'s {{GPUTextureViewDescriptor/dimension}}.
                                    - |layoutBinding|.{{GPUBindGroupLayoutEntry/textureComponentType}}
                                        is compatible with |resource|'s {{GPUTextureViewDescriptor/format}}.

                                    - If |layoutBinding|.{{GPUBindGroupLayoutEntry/multisampled}} is `true`:
                                        - |resource|'s texture's {{GPUTextureDescriptor/sampleCount}} is greater than 1.
                                    - If |layoutBinding|.{{GPUBindGroupLayoutEntry/multisampled}} is `false`:
                                        - |resource|'s texture's {{GPUTextureDescriptor/sampleCount}} is 1.

                                    - If |layoutBinding|.{{GPUBindGroupLayoutEntry/type}} is {{GPUBindingType/"sampled-texture"}}:
                                        - |resource|'s texture's {{GPUTextureDescriptor/usage}} includes
                                            {{GPUTextureUsage/SAMPLED}}.

                                    - If |layoutBinding|.{{GPUBindGroupLayoutEntry/type}} is
                                        {{GPUBindingType/"readonly-storage-texture"}} or
                                        {{GPUBindingType/"writeonly-storage-texture"}}:
                                        - |resource|.{{GPUTextureView/[[descriptor]]}}.{{GPUTextureViewDescriptor/format}}
                                            is equal to |layoutBinding|.{{GPUBindGroupLayoutEntry/storageTextureFormat}}.
                                        - |resource|'s texture's {{GPUTextureDescriptor/usage}} includes
                                            {{GPUTextureUsage/STORAGE}}.

                                - If |layoutBinding|.{{GPUBindGroupLayoutEntry/type}} is
                                    {{GPUBindingType/"uniform-buffer"}} or
                                    {{GPUBindingType/"storage-buffer"}} or
                                    {{GPUBindingType/"readonly-storage-buffer"}}:
                                    - |resource| is a {{GPUBufferBinding}}.
                                    - |resource|.{{GPUBufferBinding/buffer}} is [$valid to use with$] |this|.
                                    - Let |bufferBinding| be |bindingDescriptor|.{{GPUBindGroupEntry/resource}},
                                        a {{GPUBufferBinding}}.

                                    - If |layoutBinding|.{{GPUBindGroupLayoutEntry/type}} is {{GPUBindingType/"uniform-buffer"}}:
                                        - |bufferBinding|.{{GPUBufferBinding/buffer}}.{{GPUBufferDescriptor/usage}}
                                            includes {{GPUBufferUsage/UNIFORM}}.
                                        - |bufferBinding|.{{GPUBufferBinding/size}} &le; {{GPULimits/maxUniformBufferBindingSize}}.

                                        Issue: This validation should take into account the default when  {{GPUBufferBinding/size}} is not set.
                                        Also should {{GPUBufferBinding/size}} default to the `buffer.byteLength - offset` or
                                        `min(buffer.byteLength - offset, limits.maxUniformBufferBindingSize)`?

                                    - If |layoutBinding|.{{GPUBindGroupLayoutEntry/type}} is
                                        {{GPUBindingType/"storage-buffer"}} or
                                        {{GPUBindingType/"readonly-storage-buffer"}}:
                                        - |bufferBinding|.{{GPUBufferBinding/buffer}}.{{GPUBufferDescriptor/usage}}
                                            includes {{GPUBufferUsage/STORAGE}}.

                                    - The bound part designated by |bufferBinding|.{{GPUBufferBinding/offset}} and
                                        |bufferBinding|.{{GPUBufferBinding/size}} resides inside the buffer.

                                    - If |layoutBinding|.{{GPUBindGroupLayoutEntry/minBufferBindingSize}}
                                        is not `undefined`:
                                        - The effective binding size, that is either explict in
                                            |bufferBinding|.{{GPUBufferBinding/size}} or derived from
                                            |bufferBinding|.{{GPUBufferBinding/offset}} and the full
                                            size of the buffer, is greater than or equal to
                                            |layoutBinding|.{{GPUBindGroupLayoutEntry/minBufferBindingSize}}.
                        </div>

                        Then:
                            1. Generate a {{GPUValidationError}} in the current scope with appropriate
                                error message.
                            1. Make |bindGroup| [=invalid=] and return |bindGroup|.

                    1. Let |bindGroup|.{{GPUBindGroup/[[layout]]}} =
                        |descriptor|.{{GPUBindGroupDescriptor/layout}}.
                    1. Let |bindGroup|.{{GPUBindGroup/[[entries]]}} =
                        |descriptor|.{{GPUBindGroupDescriptor/entries}}.
                    1. Let |bindGroup|.{{GPUBindGroup/[[usedBuffers]]}} = union of the buffer usages
                        across all entries.
                    1. Let |bindGroup|.{{GPUBindGroup/[[usedTextures]]}} = union of the texture
                        [=subresource=] usages across all entries.

                    1. For each {{GPUBindGroupEntry}} |bindingDescriptor| in
                        |descriptor|.{{GPUBindGroupDescriptor/entries}}:
                        1. If |layoutBinding|.{{GPUBindGroupLayoutEntry/type}} is
                            {{GPUBindingType/"sampled-texture"}}:
                            1. Each texture [=subresource=] seen by |resource| is added
                                to {{GPUBindGroup/[[usedTextures]]}} with
                                {{GPUTextureUsage/SAMPLED}} flag.

                        1. If |layoutBinding|.{{GPUBindGroupLayoutEntry/type}} is
                            {{GPUBindingType/"readonly-storage-texture"}} or
                            {{GPUBindingType/"writeonly-storage-texture"}}:
                            1. Each texture [=subresource=] seen by |resource| is added to
                                {{GPUBindGroup/[[usedTextures]]}} with {{GPUTextureUsage/STORAGE}}
                                flag.

                        1. If |layoutBinding|.{{GPUBindGroupLayoutEntry/type}} is
                            {{GPUBindingType/"uniform-buffer"}}:
                            1. The buffer is added to the {{GPUBindGroup/[[usedBuffers]]}}
                                map with {{GPUBufferUsage/UNIFORM}} flag.

                        1. If |layoutBinding|.{{GPUBindGroupLayoutEntry/type}} is
                            {{GPUBindingType/"storage-buffer"}} or
                            {{GPUBindingType/"readonly-storage-buffer"}}:
                            1. The buffer is added to the {{GPUBindGroup/[[usedBuffers]]}}
                                map with {{GPUBufferUsage/STORAGE}} flag.
                </div>
            1. Return |bindGroup|.

            Issue: define the "effective buffer binding size" separately.
        </div>
</dl>

## GPUPipelineLayout ## {#pipeline-layout}

A {{GPUPipelineLayout}} defines the mapping between resources of all {{GPUBindGroup}} objects set up during command encoding in {{GPUProgrammablePassEncoder/setBindGroup(index, bindGroup, dynamicOffsets)|setBindGroup}}, and the shaders of the pipeline set by {{GPURenderEncoderBase/setPipeline(pipeline)|GPURenderEncoderBase.setPipeline}} or {{GPUComputePassEncoder/setPipeline(pipeline)|GPUComputePassEncoder.setPipeline}}.

The full binding address of a resource can be defined as a trio of:
  1. shader stage mask, to which the resource is visible
  2. bind group index
  3. binding number

The components of this address can also be seen as the binding space of a pipeline. A {{GPUBindGroup}} (with the corresponding {{GPUBindGroupLayout}}) covers that space for a fixed bind group index. The contained bindings need to be a superset of the resources used by the shader at this bind group index.

<script type=idl>
[Serializable]
interface GPUPipelineLayout {
};
GPUPipelineLayout includes GPUObjectBase;
</script>

{{GPUPipelineLayout}} has the following internal slots:

<dl dfn-type=attribute dfn-for="GPUPipelineLayout">
    : <dfn>\[[bindGroupLayouts]]</dfn> of type sequence<{{GPUBindGroupLayout}}>.
    ::
        The {{GPUBindGroupLayout}} objects provided at creation in {{GPUPipelineLayoutDescriptor/bindGroupLayouts|GPUPipelineLayoutDescriptor.bindGroupLayouts}}.
</dl>

Note: using the same {{GPUPipelineLayout}} for many {{GPURenderPipeline}} or {{GPUComputePipeline}} pipelines guarantees that the user agent doesn't need to rebind any resources internally when there is a switch between these pipelines.

<div class="example">
{{GPUComputePipeline}} object X was created with {{GPUPipelineLayout/[[bindGroupLayouts]]|GPUPipelineLayout.bindGroupLayouts}} A, B, C. {{GPUComputePipeline}} object Y was created with {{GPUPipelineLayout/[[bindGroupLayouts]]|GPUPipelineLayout.bindGroupLayouts}} A, D, C. Supposing the command encoding sequence has two dispatches:

  1. {{GPUProgrammablePassEncoder/setBindGroup(index, bindGroup, dynamicOffsets)|setBindGroup(0, ...)}}
  1. {{GPUProgrammablePassEncoder/setBindGroup(index, bindGroup, dynamicOffsets)|setBindGroup(1, ...)}}
  1. {{GPUProgrammablePassEncoder/setBindGroup(index, bindGroup, dynamicOffsets)|setBindGroup(2, ...)}}
  1. {{GPUComputePassEncoder/setPipeline(pipeline)|setPipeline(X)}}
  1. {{GPUComputePassEncoder/dispatch(x, y, z)|dispatch()}}
  1. {{GPUProgrammablePassEncoder/setBindGroup(index, bindGroup, dynamicOffsets)|setBindGroup(1, ...)}}
  1. {{GPUComputePassEncoder/setPipeline(pipeline)|setPipeline(Y)}}
  1. {{GPUComputePassEncoder/dispatch(x, y, z)|dispatch()}}

In this scenario, the user agent would have to re-bind the group slot 2 for the second dispatch, even though neither the {{GPUBindGroupLayout}} at index 2 of {{GPUPipelineLayout/[[bindGroupLayouts]]|GPUPipelineLayout.bindGrouplayouts}}, or the {{GPUBindGroup}} at slot 2, change.
</div>

Issue: should this example and the note be moved to some "best practices" document?

Note: the expected usage of the {{GPUPipelineLayout}} is placing the most common and the least frequently changing bind groups at the "bottom" of the layout, meaning lower bind group slot numbers, like 0 or 1. The more frequently a bind group needs to change between draw calls, the higher its index should be. This general guideline allows the user agent to minimize state changes between draw calls, and consequently lower the CPU overhead.

### Creation ### {#pipeline-layout-creation}

A {{GPUPipelineLayout}} is created via {{GPUDevice/createPipelineLayout()|GPUDevice.createPipelineLayout()}}.

<script type=idl>
dictionary GPUPipelineLayoutDescriptor : GPUObjectDescriptorBase {
    required sequence<GPUBindGroupLayout> bindGroupLayouts;
};
</script>

<dl dfn-type=method dfn-for=GPUDevice>
    : <dfn>createPipelineLayout(descriptor)</dfn>
    ::

        <div algorithm=GPUDevice.createPipelineLayout>
            **Called on:** {{GPUDevice}} |this|.

            **Arguments:**
            <pre class=argumentdef for="GPUDevice/createPipelineLayout(descriptor)">
                |descriptor|:
            </pre>

            **Returns:** {{GPUBuffer}}

            1. If any of the following conditions are unsatisfied:
                <div class=validusage>
                    - |this| is a [=valid=] {{GPUDevice}}.
                    - There is {{GPULimits/maxBindGroups|GPULimits.maxBindGroups}} or fewer
                        elements in |descriptor|.{{GPUPipelineLayoutDescriptor/bindGroupLayouts}}.
                    - Every {{GPUBindGroupLayout}} in |descriptor|.{{GPUPipelineLayoutDescriptor/bindGroupLayouts}}
                        is [$valid to use with$] |this|.
                </div>

                Then:
                    1. Generate a {{GPUValidationError}} in the current scope with appropriate error message.
                    1. Create a new [=invalid=] {{GPUPipelineLayout}} and return the result.

            1. Let |pl| be a new {{GPUPipelineLayout}} object.
            1. Set the |pl|.{{GPUPipelineLayout/[[bindGroupLayouts]]}} to
                |descriptor|.{{GPUPipelineLayoutDescriptor/bindGroupLayouts}}.
            1. Return |pl|.

            Issue: there will be more limits applicable to the whole pipeline layout.
        </div>
</dl>

Note: two {{GPUPipelineLayout}} objects are considered equivalent for any usage
if their internal {{GPUPipelineLayout/[[bindGroupLayouts]]}} sequences contain
{{GPUBindGroupLayout}} objects that are [=group-equivalent=].

# Shader Modules # {#shader-modules}

## GPUShaderModule ## {#shader-module}

<script type=idl>
enum GPUCompilationMessageType {
    "error",
    "warning",
    "info"
};

[Serializable]
interface GPUCompilationMessage {
    readonly attribute DOMString message;
    readonly attribute GPUCompilationMessageType type;
    readonly attribute unsigned long long lineNum;
    readonly attribute unsigned long long linePos;
};

[Serializable]
interface GPUCompilationInfo {
    readonly attribute FrozenArray<GPUCompilationMessage> messages;
};

[Serializable]
interface GPUShaderModule {
    Promise<GPUCompilationInfo> compilationInfo();
};
GPUShaderModule includes GPUObjectBase;
</script>

{{GPUShaderModule}} is {{Serializable}}. It is a reference to an internal
shader module object, and {{Serializable}} means that the reference can be
*copied* between realms (threads/workers), allowing multiple realms to access
it concurrently. Since {{GPUShaderModule}} is immutable, there are no race
conditions.

### Shader Module Creation ### {#shader-module-creation}

<script type=idl>
dictionary GPUShaderModuleDescriptor : GPUObjectDescriptorBase {
    required USVString code;
    object sourceMap;
};
</script>

{{GPUShaderModuleDescriptor/sourceMap}}, if defined, MAY be interpreted as a
source-map-v3 format. (https://sourcemaps.info/spec.html)
Source maps are optional, but serve as a standardized way to support dev-tool
integration such as source-language debugging.

<dl dfn-type=method dfn-for=GPUDevice>
    : <dfn>createShaderModule(descriptor)</dfn>
    ::
        Creates a new {{GPUShaderModule}}.

        <div algorithm=GPUDevice.createShaderModule>
            **Called on:** {{GPUDevice}} this.

            **Arguments:**
            <pre class=argumentdef for="GPUDevice/createShaderModule(descriptor)">
                descriptor:
            </pre>

            **Returns:** {{GPUShaderModule}}

            Issue: Describe {{GPUDevice/createShaderModule()}} algorithm steps.
        </div>
</dl>

### Shader Module Compilation Information ### {#shader-module-compilation-information}

<dl dfn-type=method dfn-for=GPUShaderModule>
    : <dfn>compilationInfo()</dfn>
    ::
        Returns any messages generated during the {{GPUShaderModule}}'s compilation.

        <div algorithm=GPUShaderModule.compilationInfo>
            **Called on:** {{GPUShaderModule}} this.

            **Returns:** Promise<{{GPUCompilationInfo}}>

            Issue: Describe {{GPUShaderModule/compilationInfo()}} algorithm steps.
        </div>
</dl>

# Pipelines # {#pipelines}

A <dfn dfn>pipeline</dfn>, be it {{GPUComputePipeline}} or {{GPURenderPipeline}},
represents the complete function done by a combination of the GPU hardware, the driver,
and the user agent, that process the input data in the shape of bindings and vertex buffers,
and produces some output, like the colors in the output render targets.

Structurally, the [=pipeline=] consists of a sequence of programmable stages (shaders)
and fixed-function states, such as the blending modes.

Note: Internally, depending on the target platform,
the driver may convert some of the fixed-function states into shader code,
and link it together with the shaders provided by the user.
This linking is one of the reason the object is created as a whole.

This combination state is created as a single object
(by {{GPUDevice/createComputePipeline(descriptor)|GPUDevice.createComputePipeline()}} or {{GPUDevice/createRenderPipeline(descriptor)|GPUDevice.createRenderPipeline()}}),
and switched as one
(by {{GPUComputePassEncoder/setPipeline(pipeline)|GPUComputePassEncoder.setPipeline}} or {{GPURenderEncoderBase/setPipeline(pipeline)|GPURenderEncoderBase.setPipeline}} correspondingly).

## Base pipelines ## {#pipeline-base}

<script type=idl>
dictionary GPUPipelineDescriptorBase : GPUObjectDescriptorBase {
    GPUPipelineLayout layout;
};

interface mixin GPUPipelineBase {
    GPUBindGroupLayout getBindGroupLayout(unsigned long index);
};
</script>

{{GPUPipelineBase}} has the following internal slots:
<dl dfn-type=attribute dfn-for="GPUPipelineBase">
    : <dfn>\[[layout]]</dfn> of type `GPUPipelineLayout`.
    ::
        The definition of the layout of resources which can be used with `this`.
</dl>

{{GPUPipelineBase}} has the following methods:
<dl dfn-type=method dfn-for=GPUPipelineBase>
    : <dfn>getBindGroupLayout(index)</dfn>
    ::

        <div algorithm=GPUPipelineBase.getBindGroupLayout>
            **Called on:** {{GPUPipelineBase}} |this|.

            **Arguments:**
            <pre class=argumentdef for="GPUPipelineBase/getBindGroupLayout(index)">
                |index|:
            </pre>

            **Returns:** {{GPUBindGroupLayout}}

            1. If |index| is greater or equal to {{GPULimits/maxBindGroups}}:
                1. Throw a {{RangeError}}.

            1. If |this| is not [=valid=]:
                1. Return a new error {{GPUBindGroupLayout}}.

            1. Return a new {{GPUBindGroupLayout}} object that references the same internal object as
                |this|.{{GPUPipelineBase/[[layout]]}}.{{GPUPipelineLayout/[[bindGroupLayouts]]}}[|index|].

            Issue: Specify this more properly once we have internal objects for {{GPUBindGroupLayout}}.
                Alternatively only spec is as a new internal objects that's [=group-equivalent=]

            Note: Only returning new {{GPUBindGroupLayout}} objects ensures no synchronization is necessary
                between the [=Content timeline=] and the [=Device timeline=].
        </div>
</dl>

### Default pipeline layout ### {#default-pipeline-layout}

A {{GPUPipelineBase}} object that was created without a {{GPUPipelineDescriptorBase/layout}}
has a default layout created and used instead.

<div algorithm="default pipeline layout creation">

    1. Let |groupDescs| be a sequence of |device|.{{device/[[limits]]}}.{{GPULimits/maxBindGroups}}
        new {{GPUBindGroupLayoutDescriptor}} objects.
    1. For each |groupDesc| in |groupDescs|:

        1. Set |groupDesc|.{{GPUBindGroupLayoutDescriptor/entries}} to an empty sequence.

    1. For each {{GPUProgrammableStageDescriptor}} |stageDesc| in the descriptor used to create the pipeline:

        1. Let |stageInfo| be the "reflection information" for |stageDesc|.

            Issue: Define the reflection information concept so that this spec can interface with the WGSL
                spec and get information what the interface is for a {{GPUShaderModule}} for a specific
                entrypoint.

        1. Let |shaderStage| be the {{GPUShaderStageFlags}} for |stageDesc|.{{GPUProgrammableStageDescriptor/entryPoint}}
            in |stageDesc|.{{GPUProgrammableStageDescriptor/module}}.
        1. For each resource |resource| in |stageInfo|'s resource interface:

            1. Let |group| be |resource|'s "group" decoration.
            1. Let |binding| be |resource|'s "binding" decoration.
            1. Let |entry| be a new {{GPUBindGroupLayoutEntry}}.
            1. Set |entry|.{{GPUBindGroupLayoutEntry/binding}} to |binding|.
            1. Set |entry|.{{GPUBindGroupLayoutEntry/visibility}} to |shaderStage|.
            1. If |resource| is for a sampler binding:

                    1. Set |entry|.{{GPUBindGroupLayoutEntry/type}} to
                        {{GPUBindingType/sampler}}.

            1. If |resource| is for a comparison sampler binding:

                1. Set |entry|.{{GPUBindGroupLayoutEntry/type}} to {{GPUBindingType/comparison-sampler}}.

            1. If |resource| is for a buffer binding:

                1. Set |entry|.{{GPUBindGroupLayoutEntry/hasDynamicOffset}} to false.

                1. If |resource| is for a uniform buffer:

                    1. Set |entry|.{{GPUBindGroupLayoutEntry/type}} to {{GPUBindingType/uniform-buffer}}.

                1. If |resource| is for a read-only storage buffer:

                    1. Set |entry|.{{GPUBindGroupLayoutEntry/type}} to {{GPUBindingType/readonly-storage-buffer}}.

                1. If |resource| is for a storage buffer:

                    1. Set |entry|.{{GPUBindGroupLayoutEntry/type}} to {{GPUBindingType/storage-buffer}}.

            1. If |resource| is for a texture binding:

                1. Set |entry|.{{GPUBindGroupLayoutEntry/textureComponentType}} to |resource|'s component type.
                1. Set |entry|.{{GPUBindGroupLayoutEntry/viewDimension}} to |resource|'s dimension.
                1. If |resource| is multisampled:

                    1. Set |entry|.{{GPUBindGroupLayoutEntry/multisampled}} to true.

                1. If |resource| is for a sampled texture:

                    1. Set |entry|.{{GPUBindGroupLayoutEntry/type}} to {{GPUBindingType/sampled-texture}}.

                1. If |resource| is for a read-only storage texture:

                    1. Set |entry|.{{GPUBindGroupLayoutEntry/type}} to {{GPUBindingType/readonly-storage-texture}}.
                    1. Set |entry|.{{GPUBindGroupLayoutEntry/storageTextureFormat}} to |resource|'s format.

                1. If |resource| is for a write-only storage texture:

                    1. Set |entry|.{{GPUBindGroupLayoutEntry/type}} to {{GPUBindingType/writeonly-storage-texture}}.
                    1. Set |entry|.{{GPUBindGroupLayoutEntry/storageTextureFormat}} to |resource|'s format.

            1. If |groupDescs|[|group|] has an entry |previousEntry| with {{GPUBindGroupLayoutEntry/binding}} equal to |binding|:

                1. If |previousEntry| is equal to |entry| up to {{GPUBindGroupLayoutEntry/visibility}}:

                    1. Add the bits set in |entry|.{{GPUBindGroupLayoutEntry/visibility}} into |previousEntry|.{{GPUBindGroupLayoutEntry/visibility}}

                1. Else

                    1. Return null (which will cause the creation of the pipeline to fail).

            1. Else

                1. Append |entry| to |groupDescs|[|group|].

    1. Let |groupLayouts| be a new sequence.
    1. For each |groupDesc| in |groupDescs|:

        1. Append |device|.{{GPUDevice/createBindGroupLayout()}}(|groupDesc|) to |groupLayouts|.

    1. Let |desc| be a new {{GPUPipelineLayoutDescriptor}}.
    1. Set |desc|.{{GPUPipelineLayoutDescriptor/bindGroupLayouts}} to |groupLayouts|.
    1. Return |device|.{{GPUDevice/createPipelineLayout()}}(|desc|).

    Issue: This fills the pipeline layout with empty bindgroups. Revisit once the behavior of empty bindgroups is specified.

</div>

### GPUProgrammableStageDescriptor ### {#GPUProgrammableStageDescriptor}

<script type=idl>
dictionary GPUProgrammableStageDescriptor {
    required GPUShaderModule module;
    required USVString entryPoint;
};
</script>

A {{GPUProgrammableStageDescriptor}} describes the entry point in the user-provided
{{GPUShaderModule}} that controls one of the programmable stages of a [=pipeline=].

<div algorithm>
    <dfn abstract-op>validating GPUProgrammableStageDescriptor</dfn>(stage, descriptor, layout)
        **Arguments:**
            - {{GPUShaderStage}} |stage|
            - {{GPUProgrammableStageDescriptor}} |descriptor|
            - {{GPUPipelineLayout}} |layout|

        1. If the |descriptor|.{{GPUProgrammableStageDescriptor/module}} is not
            a [=valid=] {{GPUShaderModule}} return false.
        1. If the |descriptor|.{{GPUProgrammableStageDescriptor/module}} doesn't contain
            an entry point at |stage| named |descriptor|.{{GPUProgrammableStageDescriptor/entryPoint}} return false.
        1. For each |binding| that is [=statically used=] by the shader entry point,
            if the result of [$validating shader binding$](|binding|, |layout|) is false, return false.
        1. Return true.
</div>

<div algorithm>
    <dfn abstract-op>validating shader binding</dfn>(binding, layout)
    **Arguments:**
        - shader |binding|, reflected from the shader module
        - {{GPUPipelineLayout}} |layout|

    Consider the shader |binding| annotation of |bindIndex| for the
    binding index and |bindGroup| for the bind group index.

    Return true if all of the following conditions are satisfied:

        1. |layout|.{{GPUPipelineLayout/[[bindGroupLayouts]]}}[|bindGroup|] contains
            a {{GPUBindGroupLayoutEntry}} |entry| whose |entry|.{{GPUBindGroupLayoutEntry/binding}} == |bindIndex|.
        1. If |entry|.{{GPUBindGroupLayoutEntry/type}} is {{GPUBindingType/"sampler"}},
            the |binding| has to be a non-comparison sampler.
        1. If |entry|.{{GPUBindGroupLayoutEntry/type}} is {{GPUBindingType/"comparison-sampler"}},
            the |binding| has to be a comparison sampler.
        1. If |entry|.{{GPUBindGroupLayoutEntry/type}} is {{GPUBindingType/"sampled-texture"}},
            the |binding| has to be a sampled texture with the component type of |entry|.{{GPUBindGroupLayoutEntry/textureComponentType}},
            and it must be multisampled if and only if |entry|.{{GPUBindGroupLayoutEntry/multisampled}} is true.
        1. If |entry|.{{GPUBindGroupLayoutEntry/type}} is {{GPUBindingType/"readonly-storage-texture"}},
            the |binding| has to be a read-only storage texture with format of |entry|.{{GPUBindGroupLayoutEntry/storageTextureFormat}}.
        1. If |entry|.{{GPUBindGroupLayoutEntry/type}} is {{GPUBindingType/"writeonly-storage-texture"}},
            the |binding| has to be a writable storage texture with format of |entry|.{{GPUBindGroupLayoutEntry/storageTextureFormat}}.
        1. If |entry|.{{GPUBindGroupLayoutEntry/type}} is {{GPUBindingType/"uniform-buffer"}},
            the |binding| has to be a uniform buffer.
        1. If |entry|.{{GPUBindGroupLayoutEntry/type}} is {{GPUBindingType/"storage-buffer"}},
            the |binding| has to be a storage buffer.
        1. If |entry|.{{GPUBindGroupLayoutEntry/type}} is {{GPUBindingType/"readonly-storage-buffer"}},
            the |binding| has to be a read-only storage buffer.
        1. If |entry|.{{GPUBindGroupLayoutEntry/type}} is {{GPUBindingType/"sampled-texture"}}, {{GPUBindingType/"readonly-storage-texture"}}, or {{GPUBindingType/"writeonly-storage-texture"}},
            the shader view dimension of the texture has to match |entry|.{{GPUBindGroupLayoutEntry/viewDimension}}.
        1. If |entry|.{{GPUBindGroupLayoutEntry/minBufferBindingSize}} is not undefined:
              - If the last field of the corresponding structure defined in the shader has an unbounded array type,
                then the value of |entry|.{{GPUBindGroupLayoutEntry/minBufferBindingSize}} must be greater than or equal to the
                byte offset of that field plus the stride of the unbounded array.
              - If the corresponding shader structure doesn't end with an unbounded array type,
                then the value of |entry|.{{GPUBindGroupLayoutEntry/minBufferBindingSize}} must be greater than or equal to the
                size of the structure.
</div>

Issue: is there a match/switch statement in bikeshed?

A resource binding is considered to be <dfn dfn>statically used</dfn> by a shader entry point
if and only if it's reachable by the control flow graph of the shader module,
starting at the entry point.

## GPUComputePipeline ## {#compute-pipeline}

A {{GPUComputePipeline}} is a kind of [=pipeline=] that controls the compute shader stage,
and can be used in {{GPUComputePassEncoder}}.

Compute inputs and outputs are all contained in the bindings,
according to the given {{GPUPipelineLayout}}.
The outputs correspond to {{GPUBindingType/"storage-buffer"}} and {{GPUBindingType/"writeonly-storage-texture"}} binding types.

Stages of a compute [=pipeline=]:
  1. Compute shader

<script type=idl>
[Serializable]
interface GPUComputePipeline {
};
GPUComputePipeline includes GPUObjectBase;
GPUComputePipeline includes GPUPipelineBase;
</script>

### Creation ### {#compute-pipeline-creation}

<script type=idl>
dictionary GPUComputePipelineDescriptor : GPUPipelineDescriptorBase {
    required GPUProgrammableStageDescriptor computeStage;
};
</script>

<dl dfn-type=method dfn-for=GPUDevice>
    : <dfn>createComputePipeline(descriptor)</dfn>
    ::
        Creates a {{GPUComputePipeline}}.

        <div algorithm=GPUDevice.createComputePipeline>
            **Called on:** {{GPUDevice}} |this|.

            **Arguments:**
            <pre class=argumentdef for="GPUDevice/createComputePipeline(descriptor)">
                |descriptor|:
            </pre>

            **Returns:** {{GPUComputePipeline}}

            If any of the following conditions are unsatisfied:
                <div class=validusage>
                    - |this| is a [=valid=] {{GPUDevice}}.
                    - |descriptor|.{{GPUPipelineDescriptorBase/layout}} is [$valid to use with$] |this|.
                    - [$validating GPUProgrammableStageDescriptor$]({{GPUShaderStage/COMPUTE}},
                        |descriptor|.{{GPUComputePipelineDescriptor/computeStage}},
                        |descriptor|.{{GPUPipelineDescriptorBase/layout}}) succeeds.
                </div>

            Then:
                1. Generate a {{GPUValidationError}} in the current scope with appropriate error message.
                1. Create a new [=invalid=] {{GPUComputePipeline}} and return the result.
        </div>
</dl>

### {{GPUDevice/createReadyComputePipeline()}} ### {#device-createReadyComputePipeline}

Same as {{GPUDevice/createComputePipeline()}}, but returns its result as a
promise which doesn't resolve until the pipeline is ready to be used without
additional delay.

If pipeline creation fails, this resolves to an [=invalid=] {{GPUComputePipeline}} object.

Issue: Define fully. (Probably by just calling directly into createComputePipeline.)

Note: Use of this method is preferred whenever possible, as it prevents
blocking [=queue timeline=] work on pipeline compilation.

## GPURenderPipeline ## {#render-pipeline}

A {{GPURenderPipeline}} is a kind of [=pipeline=] that controls the vertex
and fragment shader stages, and can be used in {{GPURenderPassEncoder}}
as well as {{GPURenderBundleEncoder}}.

Render [=pipeline=] inputs are:
  - bindings, according to the given {{GPUPipelineLayout}}
  - vertex and index buffers, described by {{GPUVertexStateDescriptor}}
  - the color attachments, described by {{GPUColorStateDescriptor}}
  - optionally, the depth-stencil attachment, described by {{GPUDepthStencilStateDescriptor}}

Render [=pipeline=] outputs are:
  - bindings of types {{GPUBindingType/"storage-buffer"}} and {{GPUBindingType/"writeonly-storage-texture"}}
  - the color attachments, described by {{GPUColorStateDescriptor}}
  - optionally, depth-stencil attachment, described by {{GPUDepthStencilStateDescriptor}}

Stages of a render [=pipeline=]:
  1. Vertex fetch, controlled by {{GPUVertexStateDescriptor}}
  2. Vertex shader
  3. Primitive assembly, controlled by {{GPUPrimitiveTopology}}
  4. Rasterization, controlled by {{GPURasterizationStateDescriptor}}
  5. Fragment shader
  6. Stencil test and operation, controlled by {{GPUDepthStencilStateDescriptor}}
  7. Depth test and write, controlled by {{GPUDepthStencilStateDescriptor}}
  8. Output merging, controlled by {{GPUColorStateDescriptor}}

Issue: we need a deeper description of these stages

<script type=idl>
[Serializable]
interface GPURenderPipeline {
};
GPURenderPipeline includes GPUObjectBase;
GPURenderPipeline includes GPUPipelineBase;
</script>

### Creation ### {#render-pipeline-creation}

<script type=idl>
dictionary GPURenderPipelineDescriptor : GPUPipelineDescriptorBase {
    required GPUProgrammableStageDescriptor vertexStage;
    GPUProgrammableStageDescriptor fragmentStage;

    required GPUPrimitiveTopology primitiveTopology;
    GPURasterizationStateDescriptor rasterizationState = {};
    required sequence<GPUColorStateDescriptor> colorStates;
    GPUDepthStencilStateDescriptor depthStencilState;
    GPUVertexStateDescriptor vertexState = {};

    GPUSize32 sampleCount = 1;
    GPUSampleMask sampleMask = 0xFFFFFFFF;
    boolean alphaToCoverageEnabled = false;
};
</script>

- {{GPURenderPipelineDescriptor/vertexStage}} describes
    the vertex shader entry point of the [=pipeline=]
- {{GPURenderPipelineDescriptor/fragmentStage}} describes
    the fragment shader entry point of the [=pipeline=]. If it's "null", the [[#no-color-output]] mode is enabled.
- {{GPURenderPipelineDescriptor/primitiveTopology}} configures
    the primitive assembly stage of the [=pipeline=].
- {{GPURenderPipelineDescriptor/rasterizationState}} configures
    the rasterization stage of the [=pipeline=].
- {{GPURenderPipelineDescriptor/colorStates}} describes
    the color attachments that are written by the [=pipeline=].
- {{GPURenderPipelineDescriptor/depthStencilState}} describes
    the optional depth-stencil attachment that is written by the [=pipeline=].
- {{GPURenderPipelineDescriptor/vertexState}} configures
    the vertex fetch stage of the [=pipeline=].
    - If {{GPURenderPipelineDescriptor/primitiveTopology}} is
        {{GPUPrimitiveTopology/"line-strip"}} or
        {{GPUPrimitiveTopology/"triangle-strip"}},
        {{GPURenderPipelineDescriptor/vertexState}}.{{GPUVertexStateDescriptor/indexFormat}}
        must be specified.

        Otherwise, it must be unspecified.
- {{GPURenderPipelineDescriptor/sampleCount}} is
    the number of MSAA samples that each attachment has to have.
- {{GPURenderPipelineDescriptor/sampleMask}} is
    a binary mask of MSAA samples, according to [[#sample-masking]].
- {{GPURenderPipelineDescriptor/alphaToCoverageEnabled}} enables the [[#alpha-to-coverage]] mode.

Issue(https://github.com/gpuweb/gpuweb/issues/936):
Refactor the shape of the render pipeline descriptor to clearly enumerate the
(ordered) list of pipeline stages. And start formalizing the spec text.

### No Color Output ### {#no-color-output}

In no-color-output mode, [=pipeline=] does not produce any color attachment outputs,
and the {{GPURenderPipelineDescriptor/colorStates}} is expected to be empty.

The [=pipeline=] still performs rasterization and produces depth values
based on the vertex position output. The depth testing and stencil operations can still be used.

### Alpha to Coverage ### {#alpha-to-coverage}

In alpha-to-coverage mode, an additional <dfn dfn>alpha-to-coverage mask</dfn>
of MSAA samples is generated based on the |alpha| component of the
fragment shader output value of the {{GPURenderPipelineDescriptor/colorStates}}[0].

The algorithm of producing the extra mask is platform-dependent. It guarantees that:
  - if |alpha| is 0.0 or less, the result is 0x0
  - if |alpha| is 1.0 or greater, the result is 0xFFFFFFFF
  - if |alpha| is greater than some other |alpha1|,
    then the produced sample mask has at least as many bits set to 1 as the mask for |alpha1|

### Sample Masking ### {#sample-masking}

The <dfn dfn>final sample mask</dfn> for a pixel is computed as:
[=rasterization mask=] & {{GPURenderPipelineDescriptor/sampleMask}} & [=shader-output mask=].

Only the lower {{GPURenderPipelineDescriptor/sampleCount}} bits of the mask are considered.

If the least-significant bit at position |N| of the [=final sample mask=] has value of "0",
the sample color outputs (corresponding to sample |N|) to all attachments of the fragment shader are discarded.
Also, no depth test or stencil operations are executed on the relevant samples of the depth-stencil attachment.

Note: the color output for sample |N| is produced by the fragment shader execution
with SV_SampleIndex == |N| for the current pixel.
If the fragment shader doesn't use this semantics, it's only executed once per pixel.

The <dfn dfn>rasterization mask</dfn> is produced by the rasterization stage,
based on the shape of the rasterized polygon. The samples incuded in the shape get the relevant
bits 1 in the mask.

The <dfn dfn>shader-output mask</dfn> takes the output value of SV_Coverage semantics in the fragment shader.
If the semantics is not [=statically used=] by the shader, and {{GPURenderPipelineDescriptor/alphaToCoverageEnabled}}
is enabled, the [=shader-output mask=] becomes the [=alpha-to-coverage mask=]. Otherwise, it defaults to 0xFFFFFFFF.

Issue: link to the semantics of SV_SampleIndex and SV_Coverage in WGSL spec.

<dl dfn-type=method dfn-for=GPUDevice>
    : <dfn>createRenderPipeline(descriptor)</dfn>
    ::

        Creates a {{GPURenderPipeline}}.

        <div algorithm=GPUDevice.createRenderPipeline>
            **Called on:** {{GPUDevice}} |this|.

            **Arguments:**
            <pre class=argumentdef for="GPUDevice/createRenderPipeline(descriptor)">
                |descriptor|:
            </pre>

            **Returns:** {{GPUBuffer}}

            If any of the following conditions are unsatisfied:
                <div class=validusage>
                    - |this| is a [=valid=] {{GPUDevice}}.
                    - |descriptor|.{{GPUPipelineDescriptorBase/layout}} is [$valid to use with$] |this|.
                    - [$validating GPUProgrammableStageDescriptor$]({{GPUShaderStage/VERTEX}},
                        |descriptor|.{{GPURenderPipelineDescriptor/vertexStage}},
                        |descriptor|.{{GPUPipelineDescriptorBase/layout}}) succeeds.
                    - If |descriptor|.{{GPURenderPipelineDescriptor/fragmentStage}} is not `null`:
                        - [$validating GPUProgrammableStageDescriptor$]({{GPUShaderStage/FRAGMENT}},
                            |descriptor|.{{GPURenderPipelineDescriptor/fragmentStage}},
                            |descriptor|.{{GPUPipelineDescriptorBase/layout}}) succeeds.
                    - |descriptor|.{{GPURenderPipelineDescriptor/colorStates}}.length is less than
                        or equal to 4.
                    - [$validating GPUVertexStateDescriptor$](|descriptor|.{{GPURenderPipelineDescriptor/vertexState}},
                        |descriptor|.{{GPURenderPipelineDescriptor/vertexStage}}) passes.
                    - If |descriptor|.{{GPURenderPipelineDescriptor/alphaToCoverageEnabled}} is `true`:
                        - |descriptor|.{{GPURenderPipelineDescriptor/sampleCount}} is greater than 1.
                    - If the output SV_Coverage semantics is [=statically used=] by
                        |descriptor|.{{GPURenderPipelineDescriptor/fragmentStage}}:
                        - |descriptor|.{{GPURenderPipelineDescriptor/alphaToCoverageEnabled}} is `false`.
                </div>

            Then:
                1. Generate a {{GPUValidationError}} in the current scope with appropriate error message.
                1. Create a new [=invalid=] {{GPURenderPipeline}} and return the result.

            Issue: need a proper limit for the maximum number of color targets.

            Issue: need a more detailed validation of the render states.

            Issue: need description of the render states.
        </div>
</dl>

### {{GPUDevice/createReadyRenderPipeline()}} ### {#device-createReadyRenderPipeline}

Same as {{GPUDevice/createRenderPipeline()}}, but returns its result as a
promise which doesn't resolve until the pipeline is ready to be used without
additional delay.

If pipeline creation fails, this resolves to an [=invalid=] {{GPURenderPipeline}} object.

Issue: Define fully. (Probably by just calling directly into createRenderPipeline.)

Note: Use of this method is preferred whenever possible, as it prevents
blocking [=queue timeline=] work on pipeline compilation.

### Primitive Topology ### {#primitive-topology}

<script type=idl>
enum GPUPrimitiveTopology {
    "point-list",
    "line-list",
    "line-strip",
    "triangle-list",
    "triangle-strip"
};
</script>

### Rasterization State ### {#rasterization-state}

<script type=idl>
dictionary GPURasterizationStateDescriptor {
    GPUFrontFace frontFace = "ccw";
    GPUCullMode cullMode = "none";
    // Enable depth clamping (requires "depth-clamping" extension)
    boolean clampDepth = false;

    GPUDepthBias depthBias = 0;
    float depthBiasSlopeScale = 0;
    float depthBiasClamp = 0;
};
</script>

<div algorithm>
    <dfn abstract-op>validating GPURasterizationStateDescriptor</dfn>(|device|, |descriptor|)
        1. If |device| is lost return false.
        1. If |descriptor|.{{GPURasterizationStateDescriptor/clampDepth}} is true and |device|.{{device/[[extensions]]}}
            doesn't contain {{GPUExtensionName/"depth-clamping"}}, return false.
        1. Return true.
</div>

<script type=idl>
enum GPUFrontFace {
    "ccw",
    "cw"
};
</script>

<script type=idl>
enum GPUCullMode {
    "none",
    "front",
    "back"
};
</script>

### Color State ### {#color-state}

<script type=idl>
dictionary GPUColorStateDescriptor {
    required GPUTextureFormat format;

    GPUBlendDescriptor alphaBlend = {};
    GPUBlendDescriptor colorBlend = {};
    GPUColorWriteFlags writeMask = 0xF;  // GPUColorWrite.ALL
};
</script>

<script type=idl>
typedef [EnforceRange] unsigned long GPUColorWriteFlags;
interface GPUColorWrite {
    const GPUColorWriteFlags RED   = 0x1;
    const GPUColorWriteFlags GREEN = 0x2;
    const GPUColorWriteFlags BLUE  = 0x4;
    const GPUColorWriteFlags ALPHA = 0x8;
    const GPUColorWriteFlags ALL   = 0xF;
};
</script>

#### Blend State #### {#blend-state}

<script type=idl>
dictionary GPUBlendDescriptor {
    GPUBlendFactor srcFactor = "one";
    GPUBlendFactor dstFactor = "zero";
    GPUBlendOperation operation = "add";
};
</script>

<script type=idl>
enum GPUBlendFactor {
    "zero",
    "one",
    "src-color",
    "one-minus-src-color",
    "src-alpha",
    "one-minus-src-alpha",
    "dst-color",
    "one-minus-dst-color",
    "dst-alpha",
    "one-minus-dst-alpha",
    "src-alpha-saturated",
    "blend-color",
    "one-minus-blend-color"
};
</script>

<script type=idl>
enum GPUBlendOperation {
    "add",
    "subtract",
    "reverse-subtract",
    "min",
    "max"
};
</script>

### Depth/Stencil State ### {#depth-stencil-state}

<script type=idl>
dictionary GPUDepthStencilStateDescriptor {
    required GPUTextureFormat format;

    boolean depthWriteEnabled = false;
    GPUCompareFunction depthCompare = "always";

    GPUStencilStateFaceDescriptor stencilFront = {};
    GPUStencilStateFaceDescriptor stencilBack = {};

    GPUStencilValue stencilReadMask = 0xFFFFFFFF;
    GPUStencilValue stencilWriteMask = 0xFFFFFFFF;
};
</script>

<script type=idl>
dictionary GPUStencilStateFaceDescriptor {
    GPUCompareFunction compare = "always";
    GPUStencilOperation failOp = "keep";
    GPUStencilOperation depthFailOp = "keep";
    GPUStencilOperation passOp = "keep";
};
</script>

<script type=idl>
enum GPUStencilOperation {
    "keep",
    "zero",
    "replace",
    "invert",
    "increment-clamp",
    "decrement-clamp",
    "increment-wrap",
    "decrement-wrap"
};
</script>

### Vertex State ### {#vertex-state}

<script type=idl>
enum GPUIndexFormat {
    "uint16",
    "uint32"
};
</script>

#### Vertex Formats #### {#vertex-formats}

The name of the format specifies the data type of the component, the number of
values, and whether the data is normalized.

  * `uchar` = unsigned 8-bit value
  * `char` = signed 8-bit value
  * `ushort` = unsigned 16-bit value
  * `short` = signed 16-bit value
  * `half` = half-precision 16-bit floating point value
  * `float` = 32-bit floating point value
  * `uint` = unsigned 32-bit integer value
  * `int` = signed 32-bit integer value

If no number of values is given in the name, a single value is provided.
If the format has the `-bgra` suffix, it means the values are arranged as
blue, green, red and alpha values.

<script type=idl>
enum GPUVertexFormat {
    "uchar2",
    "uchar4",
    "char2",
    "char4",
    "uchar2norm",
    "uchar4norm",
    "char2norm",
    "char4norm",
    "ushort2",
    "ushort4",
    "short2",
    "short4",
    "ushort2norm",
    "ushort4norm",
    "short2norm",
    "short4norm",
    "half2",
    "half4",
    "float",
    "float2",
    "float3",
    "float4",
    "uint",
    "uint2",
    "uint3",
    "uint4",
    "int",
    "int2",
    "int3",
    "int4"
};
</script>

<script type=idl>
enum GPUInputStepMode {
    "vertex",
    "instance"
};
</script>

<script type=idl>
dictionary GPUVertexStateDescriptor {
    GPUIndexFormat indexFormat = "uint32";
    sequence<GPUVertexBufferLayoutDescriptor?> vertexBuffers = [];
};
</script>

A <dfn dfn>vertex buffer</dfn> is, conceptually, a view into buffer memory as an *array of structures*.
{{GPUVertexBufferLayoutDescriptor/arrayStride}} is the stride, in bytes, between *elements* of that array.
Each element of a vertex buffer is like a *structure* with a memory layout defined by its
{{GPUVertexBufferLayoutDescriptor/attributes}}, which describe the *members* of the structure.

Each {{GPUVertexAttributeDescriptor}} describes its
{{GPUVertexAttributeDescriptor/format}} and its
{{GPUVertexAttributeDescriptor/offset}}, in bytes, within the structure.

Each attribute appears as a separate input in a vertex shader, each bound by a numeric *location*,
which is specified by {{GPUVertexAttributeDescriptor/shaderLocation}}.
Every location must be unique within the {{GPUVertexStateDescriptor}}.

<script type=idl>
dictionary GPUVertexBufferLayoutDescriptor {
    required GPUSize64 arrayStride;
    GPUInputStepMode stepMode = "vertex";
    required sequence<GPUVertexAttributeDescriptor> attributes;
};
</script>

<script type=idl>
dictionary GPUVertexAttributeDescriptor {
    required GPUVertexFormat format;
    required GPUSize64 offset;

    required GPUIndex32 shaderLocation;
};
</script>

<div algorithm>
    <dfn abstract-op>validating GPUVertexBufferLayoutDescriptor</dfn>(descriptor, vertexStage)
    **Arguments:**
        - {{GPUVertexBufferLayoutDescriptor}} |descriptor|
        - {{GPUProgrammableStageDescriptor}} |vertexStage|

    Return true, if and only if, all of the following conditions are true:

        1. |descriptor|.{{GPUVertexBufferLayoutDescriptor/attributes}}.length is less than or equal to 16.
        1. |descriptor|.{{GPUVertexBufferLayoutDescriptor/arrayStride}} is less then or equal to 2048.
        1. Any attribute |at| in the list |descriptor|.{{GPUVertexBufferLayoutDescriptor/attributes}} has
            |at|.{{GPUVertexAttributeDescriptor/offset} + sizeOf(|at|.{{GPUVertexAttributeDescriptor/format}} less or equal to
            |descriptor|.{{GPUVertexBufferLayoutDescriptor/arrayStride}}.
        1. For every vertex attribute in the shader reflection of |vertexStage|.{{GPUProgrammableStageDescriptor/module}}
            that is know to be [=statically used=] by |vertexStage|.{{GPUProgrammableStageDescriptor/entryPoint}},
            there is a corresponding |at| element of |descriptor|.{{GPUVertexBufferLayoutDescriptor/attributes}} that:
            1. The shader format is |at|.{{GPUVertexAttributeDescriptor/format}}.
            2. The shader location is |at|.{{GPUVertexAttributeDescriptor/shaderLocation}}.
</div>

Issue(https://github.com/gpuweb/gpuweb/issues/693): add a limit to the number of vertex attributes

<div algorithm>
    <dfn abstract-op>validating GPUVertexStateDescriptor</dfn>(descriptor, vertexStage)
    **Arguments:**
        - {{GPUVertexStateDescriptor}} |descriptor|
        - {{GPUProgrammableStageDescriptor}} |vertexStage|

    Return true, if and only if, all of the following conditions are true:

        1. |descriptor|.{{GPUVertexStateDescriptor/vertexBuffers}}.length is less than or equal to 8
        1. Each |vertexBuffer| layout descriptor in the list |descriptor|.{{GPUVertexStateDescriptor/vertexBuffers}}
            passes [$validating GPUVertexBufferLayoutDescriptor$](|vertexBuffer|, |vertexStage|)
        1. Each |at| in the union of all {{GPUVertexAttributeDescriptor}}
            across |descriptor|.{{GPUVertexStateDescriptor/vertexBuffers}} has a distinct
            |at|.{{GPUVertexAttributeDescriptor/shaderLocation}} value.
</div>

Issue(https://github.com/gpuweb/gpuweb/issues/693): add a limit to the number of vertex buffers

# Command Buffers # {#command-buffers}

## GPUCommandBuffer ## {#command-buffer}

<script type=idl>
interface GPUCommandBuffer {
    readonly attribute Promise<double> executionTime;
};
GPUCommandBuffer includes GPUObjectBase;
</script>

{{GPUCommandBuffer}} has the following attributes:

<dl dfn-type=attribute dfn-for="GPUCommandBuffer">
    : <dfn>executionTime</dfn> of type Promise<{{double}}>, readonly
    ::
        The total time, in seconds, that the GPU took to execute this command buffer.

        Note:
        If {{GPUCommandEncoderDescriptor/measureExecutionTime}} is true,
        this resolves after the command buffer executes.
        Otherwise, this rejects with an {{OperationError}}.

        <div class=issue>
            Specify the creation and resolution of the promise.

            In {{GPUCommandEncoder/finish()}}, it should be specified that a
            new promise is created and stored in this attribute.
            The promise starts rejected if measureExecutionTime is false.
            If the finish() fails, then the promise resolves to 0.

            In {{GPUQueue/submit()}}, it should be specified that (if
            measureExecutionTime is set), work is issued to read back the
            execution time, and, when that completes,
            the promise is resolved with that value.
            If the submit() fails, then the promise resolves to 0.
        </div>
</dl>

### Creation ### {#command-buffer-creation}

<script type=idl>
dictionary GPUCommandBufferDescriptor : GPUObjectDescriptorBase {
};
</script>


# Command Encoding # {#command-encoding}

## GPUCommandEncoder ## {#command-encoder}

<script type=idl>
interface GPUCommandEncoder {
    GPURenderPassEncoder beginRenderPass(GPURenderPassDescriptor descriptor);
    GPUComputePassEncoder beginComputePass(optional GPUComputePassDescriptor descriptor = {});

    void copyBufferToBuffer(
        GPUBuffer source,
        GPUSize64 sourceOffset,
        GPUBuffer destination,
        GPUSize64 destinationOffset,
        GPUSize64 size);

    void copyBufferToTexture(
        GPUBufferCopyView source,
        GPUTextureCopyView destination,
        GPUExtent3D copySize);

    void copyTextureToBuffer(
        GPUTextureCopyView source,
        GPUBufferCopyView destination,
        GPUExtent3D copySize);

    void copyTextureToTexture(
        GPUTextureCopyView source,
        GPUTextureCopyView destination,
        GPUExtent3D copySize);

    void pushDebugGroup(USVString groupLabel);
    void popDebugGroup();
    void insertDebugMarker(USVString markerLabel);

    void writeTimestamp(GPUQuerySet querySet, GPUSize32 queryIndex);

    void resolveQuerySet(
        GPUQuerySet querySet,
        GPUSize32 firstQuery,
        GPUSize32 queryCount,
        GPUBuffer destination,
        GPUSize64 destinationOffset);

    GPUCommandBuffer finish(optional GPUCommandBufferDescriptor descriptor = {});
};
GPUCommandEncoder includes GPUObjectBase;
</script>

{{GPUCommandEncoder}} has the following internal slots:

<dl dfn-type=attribute dfn-for="GPUCommandEncoder">
    : <dfn>\[[state]]</dfn> of type {{encoder state}}.
    ::
        The current state of the {{GPUCommandEncoder}}, initially set to {{encoder state/open}}.

    : <dfn>\[[debug_group_stack]]</dfn> of type `sequence<USVString>`.
    ::
        A stack of active debug group labels.
</dl>

Each {{GPUCommandEncoder}} has a current <dfn dfn-type="enum">encoder state</dfn> on the [=Content timeline=]
which may be one of the following:

<dl dfn-type="enum-value" dfn-for="encoder state">
    : "<dfn>open</dfn>"
    ::
        Indicates the {{GPUCommandEncoder}} is available to begin new operations. The {{GPUCommandEncoder/[[state]]}} is
        {{encoder state/open}} any time the {{GPUCommandEncoder}} is [=valid=] and has no active
        {{GPURenderPassEncoder}} or {{GPUComputePassEncoder}}.

    : "<dfn>encoding a render pass</dfn>"
    ::
        Indicates the {{GPUCommandEncoder}} has an active {{GPURenderPassEncoder}}. The
        {{GPUCommandEncoder/[[state]]}} becomes {{encoder state/encoding a render pass}} once
        {{GPUCommandEncoder/beginRenderPass()}} is called sucessfully until {{GPURenderPassEncoder/endPass()}} is called
        on the returned {{GPURenderPassEncoder}}, at which point the {{GPUCommandEncoder/[[state]]}}
        (if the encoder is still valid) reverts to {{encoder state/open}}.

    : "<dfn>encoding a compute pass</dfn>"
    ::
        Indicates the {{GPUCommandEncoder}} has an active {{GPUComputePassEncoder}}.  The
        {{GPUCommandEncoder/[[state]]}} becomes {{encoder state/encoding a compute pass}} once
        {{GPUCommandEncoder/beginComputePass()}} is called sucessfully until {{GPUComputePassEncoder/endPass()}} is
        called on the returned {{GPUComputePassEncoder}}, at which point the {{GPUCommandEncoder/[[state]]}}
        (if the encoder is still valid) reverts to {{encoder state/open}}.

    : "<dfn>closed</dfn>"
    ::
        Indicates the {{GPUCommandEncoder}} is no longer available for any operations. The
        {{GPUCommandEncoder/[[state]]}} becomes {{encoder state/closed}} once {{GPUCommandEncoder/finish()}} is called
        or the {{GPUCommandEncoder}} otherwise becomes [=invalid=].
</dl>

### Creation ### {#command-encoder-creation}

<script type=idl>
dictionary GPUCommandEncoderDescriptor : GPUObjectDescriptorBase {
    boolean measureExecutionTime = false;

    // TODO: reusability flag?
};
</script>

<dl dfn-type=dict-member dfn-for=GPUCommandEncoderDescriptor>
    : <dfn>measureExecutionTime</dfn>
    ::
        Enable measurement of the GPU execution time of the entire command buffer.
</dl>

<dl dfn-type=method dfn-for=GPUDevice>
    : <dfn>createCommandEncoder(descriptor)</dfn>
    ::
        Creates a new {{GPUCommandEncoder}}.

        <div algorithm=GPUDevice.createCommandEncoder>
            **Called on:** {{GPUDevice}} this.

            **Arguments:**
            <pre class=argumentdef for="GPUDevice/createCommandEncoder(descriptor)">
                descriptor:
            </pre>

            **Returns:** {{GPUCommandEncoder}}

            Issue: Describe {{GPUDevice/createCommandEncoder()}} algorithm steps.
        </div>
</dl>

## Pass Encoding ## {#command-encoder-pass-encoding}

<dl dfn-type=method dfn-for=GPUCommandEncoder>
    : <dfn>beginRenderPass(descriptor)</dfn>
    ::

        Begins encoding a render pass described by |descriptor|.

        <div algorithm=GPUCommandEncoder.beginRenderPass>
            **Called on:** {{GPUCommandEncoder}} |this|.

            **Arguments:**
            <pre class=argumentdef for="GPUCommandEncoder/beginRenderPass(descriptor)">
                |descriptor|:
            </pre>

            **Returns:** {{GPURenderPassEncoder}}

            Issue the following steps on the [=Device timeline=] of |this|:
            <div class=device-timeline>
                1. If any of the following conditions are unsatisfied, generate a validation
                    error and stop.
                    <div class=validusage>
                        - |this|.{{GPUCommandEncoder/[[state]]}} is {{encoder state/open}}.
                        - |descriptor| meets the
                            [$GPURenderPassDescriptor/GPURenderPassDescriptor Valid Usage$] rules.
                    </div>
                1. Set |this|.{{GPUCommandEncoder/[[state]]}} to {{encoder state/encoding a render pass}}.
                1. For each |colorAttachment| in |descriptor|.{{GPURenderPassDescriptor/colorAttachments}}:
                    1. The texture [=subresource=] seen by |colorAttachment|.{{GPURenderPassColorAttachmentDescriptor/attachment}}
                        is considered to be used as {{GPUTextureUsage/OUTPUT_ATTACHMENT}} for the
                        duration of the render pass.
                1. Let |depthStencilAttachment| be |descriptor|.{{GPURenderPassDescriptor/depthStencilAttachment}}.
                1. If |depthStencilAttachment| is not `null`:
                    1. The texture [=subresource=] seen by |depthStencilAttachment|.{{GPURenderPassDepthStencilAttachmentDescriptor/attachment}}
                        is considered to be used as {{GPUTextureUsage/OUTPUT_ATTACHMENT}} for the
                        duration of the render pass.
            </div>

            Issue: specify the behavior of read-only depth/stencil
        </div>

    : <dfn>beginComputePass(descriptor)</dfn>
    ::

        Begins encoding a compute pass described by |descriptor|.

        <div algorithm=GPUCommandEncoder.beginComputePass>
            **Called on:** {{GPUCommandEncoder}} |this|.

            **Arguments:**
            <pre class=argumentdef for="GPUCommandEncoder/beginComputePass(descriptor)">
                descriptor:
            </pre>

            **Returns:** {{GPUComputePassEncoder}}

            Issue the following steps on the [=Device timeline=] of |this|:
            <div class=device-timeline>
                1. If any of the following conditions are unsatisfied, generate a validation
                    error and stop.
                    <div class=validusage>
                        - |this|.{{GPUCommandEncoder/[[state]]}} is {{encoder state/open}}.
                    </div>
                1. Set |this|.{{GPUCommandEncoder/[[state]]}} to {{encoder state/encoding a compute pass}}.
            </div>
        </div>
</dl>

## Copy Commands ## {#copy-commands}

### <dfn dictionary>GPUTextureDataLayout</dfn> ### {#gpu-texture-data-layout}

<script type=idl>
dictionary GPUTextureDataLayout {
    GPUSize64 offset = 0;
    required GPUSize32 bytesPerRow;
    GPUSize32 rowsPerImage = 0;
};
</script>

A {{GPUTextureDataLayout}} is a layout of <dfn dfn>images</dfn> within some linear memory.
It's used when copying data between a [=texture=] and a [=buffer=], or when scheduling a
write into a [=texture=] from the {{GPUQueue}}.

  - For {{GPUTextureDimension/2d}} textures, data is copied between one or multiple contiguous [=images=] and [=array layers=].
  - For {{GPUTextureDimension/3d}} textures, data is copied between one or multiple contiguous [=images=] and depth [=slices=].

Issue: Define images more precisely. In particular, define them as being comprised of [=texel blocks=].

Issue: Define the exact copy semantics, by reference to common algorithms shared by the copy methods.

<dl dfn-type=dict-member dfn-for=GPUTextureDataLayout>
    : <dfn>bytesPerRow</dfn>
    ::
        The stride, in bytes, between the beginning of each row of [=texel blocks=] and the subsequent row.

    : <dfn>rowsPerImage</dfn>
    ::
        {{GPUTextureDataLayout/rowsPerImage}} &divide; [=texel block height=] &times;
        {{GPUTextureDataLayout/bytesPerRow}} is the stride, in bytes, between the beginning of each [=image=]
        of data and the subsequent [=image=].
</dl>

### <dfn dictionary>GPUBufferCopyView</dfn> ### {#gpu-buffer-copy-view}

<script type=idl>
dictionary GPUBufferCopyView : GPUTextureDataLayout {
    required GPUBuffer buffer;
};
</script>

A {{GPUBufferCopyView}} contains the actual [=texture=] data placed in a [=buffer=] according to {{GPUTextureDataLayout}}.

<div algorithm class=validusage>
<dfn abstract-op>validating GPUBufferCopyView</dfn>

  **Arguments:**
    - {{GPUBufferCopyView}} |bufferCopyView|

  **Returns:** boolean

  Return true if and only if all of the following conditions apply:
    - |bufferCopyView|.{{GPUBufferCopyView/buffer}} must be a [=valid=] {{GPUBuffer}}.
    - |bufferCopyView|.{{GPUTextureDataLayout/bytesPerRow}} must be a multiple of 256.

</div>

### <dfn dictionary>GPUTextureCopyView</dfn> ### {#gpu-texture-copy-view}

<script type=idl>
dictionary GPUTextureCopyView {
    required GPUTexture texture;
    GPUIntegerCoordinate mipLevel = 0;
    GPUOrigin3D origin = {};
};
</script>

A {{GPUTextureCopyView}} is a view of a sub-region of one or multiple contiguous [=texture=] [=subresources=] with the initial
offset {{GPUOrigin3D}} in texels, used when copying data from or to a {{GPUTexture}}.

  * {{GPUTextureCopyView/origin}}: If unspecified, defaults to `[0, 0, 0]`.

<div algorithm class=validusage>
<dfn abstract-op>validating GPUTextureCopyView</dfn>

  **Arguments:**
    - {{GPUTextureCopyView}} |textureCopyView|

  **Returns:** boolean

  Let:
  - |blockWidth| be the [=texel block width=] of |textureCopyView|.{{GPUTextureCopyView/texture}}.{{GPUTexture/[[format]]}}.
  - |blockHeight| be the [=texel block height=] of |textureCopyView|.{{GPUTextureCopyView/texture}}.{{GPUTexture/[[format]]}}.

  Return true if and only if all of the following conditions apply:
  - |textureCopyView|.{{GPUTextureCopyView/texture}} must be a [=valid=] {{GPUTexture}}.
  - |textureCopyView|.{{GPUTextureCopyView/mipLevel}} must be less than the {{GPUTexture/[[mipLevelCount]]}} of
    |textureCopyView|.{{GPUTextureCopyView/texture}}.
  - |textureCopyView|.{{GPUTextureCopyView/origin}}.[=Origin3D/x=] must be a multiple of |blockWidth|.
  - |textureCopyView|.{{GPUTextureCopyView/origin}}.[=Origin3D/y=] must be a multiple of |blockHeight|.

</div>

Issue(gpuweb/gpuweb#69): Define the copies with {{GPUTextureDimension/1d}} and {{GPUTextureDimension/3d}} textures.

### <dfn dictionary>GPUImageBitmapCopyView</dfn> ### {#gpu-image-bitmap-copy-view}

<script type=idl>
dictionary GPUImageBitmapCopyView {
    required ImageBitmap imageBitmap;
    GPUOrigin2D origin = {};
};
</script>

  * {{GPUImageBitmapCopyView/origin}}: If unspecified, defaults to `[0, 0]`.

<dl dfn-type=method dfn-for=GPUCommandEncoder>
    : <dfn>copyBufferToBuffer(source, sourceOffset, destination, destinationOffset, size)</dfn>
    ::
        Encode a command into the {{GPUCommandEncoder}} that copies data from a sub-region of a
        {{GPUBuffer}} to a sub-region of another {{GPUBuffer}}.

        <div algorithm=GPUCommandEncoder.copyBufferToBuffer>
            **Called on:** {{GPUCommandEncoder}} |this|.

            **Arguments:**
            <pre class=argumentdef for="GPUCommandEncoder/copyBufferToBuffer(source, sourceOffset, destination, destinationOffset, size)">
                |source|: The {{GPUBuffer}} to copy from.
                |sourceOffset|: Offset in bytes into |source| to begin copying from.
                |destination|: The {{GPUBuffer}} to copy to.
                |destinationOffset|: Offset in bytes into |destination| to place the copied data.
                |size|: Bytes to copy.
            </pre>

            **Returns:** `void`

            If any of the following conditions are unsatisfied, generate a validation error and stop.
            <div class=validusage>
                - |this|.{{GPUCommandEncoder/[[state]]}} is {{encoder state/open}}.
                - |source| is [$valid to use with$] |this|.
                - |destination| is [$valid to use with$] |this|.
                - |source|.{{GPUBuffer/[[usage]]}} contains {{GPUBufferUsage/COPY_SRC}}.
                - |destination|.{{GPUBuffer/[[usage]]}} contains {{GPUBufferUsage/COPY_DST}}.
                - |size| is a multiple of 4.
                - |sourceOffset| is a multiple of 4.
                - |destinationOffset| is a multiple of 4.
                - (|sourceOffset| + |size|) does not overflow a {{GPUSize64}}.
                - (|destinationOffset| + |size|) does not overflow a {{GPUSize64}}.
                - |source|.{{GPUBuffer/[[size]]}} is greater than or equal to (|sourceOffset| + |size|).
                - |destination|.{{GPUBuffer/[[size]]}} is greater than or equal to (|destinationOffset| + |size|).
                - |source| and |destination| are not the same {{GPUBuffer}}.
            </div>

            Issue(gpuweb/gpuweb#21): Define the state machine for GPUCommandEncoder.

            Issue(gpuweb/gpuweb#69): figure out how to handle overflows in the spec.
        </div>
</dl>

### Copy Between Buffer and Texture ### {#copy-between-buffer-texture}

WebGPU provides {{GPUCommandEncoder/copyBufferToTexture()}} for buffer-to-texture copies and
{{GPUCommandEncoder/copyTextureToBuffer()}} for texture-to-buffer copies.

The following definitions and validation rules apply to both {{GPUCommandEncoder/copyBufferToTexture()}}
and {{GPUCommandEncoder/copyTextureToBuffer()}}.

[=textureCopyView subresource size=] and [=Valid Texture Copy Range=] also applies to
{{GPUCommandEncoder/copyTextureToTexture()}}.

<div algorithm="textureCopyView subresource size">

<dfn dfn>textureCopyView subresource size</dfn>

  **Arguments:**
    - {{GPUTextureCopyView}} |textureCopyView|

  **Returns:**
    - {{GPUExtent3D}}

  The [=textureCopyView subresource size=] of |textureCopyView| is calculated as follows:

  Its [=Extent3D/width=], [=Extent3D/height=] and [=Extent3D/depth=] are the width, height, and depth, respectively,
  of the [=physical size=] of |textureCopyView|.{{GPUTextureCopyView/texture}} [=subresource=] at [=mipmap level=]
  |textureCopyView|.{{GPUTextureCopyView/mipLevel}}.

</div>

Issue: define this as an algorithm with (texture, mipmapLevel) parameters and use the call syntax instead of referring to the definition by label.

<div algorithm class=validusage>
    <dfn abstract-op>validating linear texture data</dfn>(layout, byteSize, format, copyExtent)

    **Arguments:**
        - {{GPUTextureDataLayout}} |layout| of the linear texture data
        - {{GPUSize64}} |byteSize| - total size of the linear data, in bytes
        - {{GPUTextureFormat}} |format| of the texture
        - {{GPUExtent3D}} |copyExtent| - extent of the texture to copy

    Let:
        - |blockWidth| be the [=texel block width=] of |format|.
        - |blockHeight| be the [=texel block height=] of |format|.
        - |blockSize| be the [=texel block size=] of |format|.
        - |bytesInACompleteRow| be |blockSize| &times; |copyExtent|.[=Extent3D/width=] &div; |blockWidth|.
        - |requiredBytesInCopy| be calculated with the following algorithm assuming all the parameters are [=valid=]:
            ```
            if (copyExtent.width == 0 || copyExtent.height == 0 || copyExtent.depth == 0) {
                requiredBytesInCopy = 0;
            } else {
                GPUSize64 texelBlockRowsPerImage = layout.rowsPerImage / blockHeight;
                GPUSize64 bytesPerImage = layout.bytesPerRow * texelBlockRowsPerImage;
                GPUSize64 bytesInLastSlice =
                    layout.bytesPerRow * (copyExtent.height / blockHeight - 1) + (copyExtent.width / blockWidth * blockSize);
                requiredBytesInCopy = bytesPerImage * (copyExtent.depth - 1) + bytesInLastSlice;
            }
            ```

    The following validation rules apply:

    For the copy being in-bounds:
    - If |layout|.{{GPUTextureDataLayout/rowsPerImage}} is not 0, it must be greater than or equal to
        |copyExtent|.[=Extent3D/height=].
    - (|layout|.{{GPUTextureDataLayout/offset}} + |requiredBytesInCopy|) must not overflow a {{GPUSize64}}.
    - (|layout|.{{GPUTextureDataLayout/offset}} + |requiredBytesInCopy|) must be smaller than or equal to |byteSize|.

    For the texel block alignments:
    - |layout|.{{GPUTextureDataLayout/rowsPerImage}} must be a multiple of |blockHeight|.
    - |layout|.{{GPUTextureDataLayout/offset}} must be a multiple of |blockSize|.

    For other members in |layout|:
    - If |copyExtent|.[=Extent3D/height=] is greater than 1 or |copyExtent|.[=Extent3D/depth=] is greater than 1:
        - |layout|.{{GPUTextureDataLayout/bytesPerRow}} must be greater than or equal to the number of |bytesInACompleteRow|.
    - If |copyExtent|.[=Extent3D/depth=] is greater than 1:
        - |layout|.{{GPUTextureDataLayout/rowsPerImage}} must be greater than or equal to |copyExtent|.[=Extent3D/height=].
</div>

<div algorithm class=validusage>

<dfn dfn>Valid Texture Copy Range</dfn>

Given a {{GPUTextureCopyView}} |textureCopyView| and a {{GPUExtent3D}} |copySize|, let
  - |blockWidth| be the [=texel block width=] of |textureCopyView|.{{GPUTextureCopyView/texture}}.{{GPUTexture/[[format]]}}.
  - |blockHeight| be the [=texel block height=] of |textureCopyView|.{{GPUTextureCopyView/texture}}.{{GPUTexture/[[format]]}}.

The following validation rules apply:

  - If the {{GPUTexture/[[dimension]]}} of |textureCopyView|.{{GPUTextureCopyView/texture}} is
    {{GPUTextureDimension/1d}}:
    - Both |copySize|.[=Extent3D/height=] and [=Extent3D/depth=] must be 1.
  - If the {{GPUTexture/[[dimension]]}} of |textureCopyView|.{{GPUTextureCopyView/texture}} is
    {{GPUTextureDimension/2d}}:
     -  (|textureCopyView|.{{GPUTextureCopyView/origin}}.[=Origin3D/x=] + |copySize|.[=Extent3D/width=]),
        (|textureCopyView|.{{GPUTextureCopyView/origin}}.[=Origin3D/y=] + |copySize|.[=Extent3D/height=]), and
        (|textureCopyView|.{{GPUTextureCopyView/origin}}.[=Origin3D/z=] + |copySize|.[=Extent3D/depth=])
        must be less than or equal to the
        [=Extent3D/width=], [=Extent3D/height=], and [=Extent3D/depth=], respectively,
        of the [=textureCopyView subresource size=] of |textureCopyView|.
  - |copySize|.[=Extent3D/width=] must be a multiple of |blockWidth|.
  - |copySize|.[=Extent3D/height=] must be a multiple of |blockHeight|.

</div>

Issue(gpuweb/gpuweb#69): Define the copies with {{GPUTextureDimension/1d}} and
{{GPUTextureDimension/3d}} textures.

Issue(gpuweb/gpuweb#537): Additional restrictions on rowsPerImage if needed.

Issue(gpuweb/gpuweb#652): Define the copies with {{GPUTextureFormat/"depth24plus"}} and
{{GPUTextureFormat/"depth24plus-stencil8"}}.

Issue: convert "Valid Texture Copy Range" into an algorithm with parameters, similar to "validating linear texture data"

<dl dfn-type=method dfn-for=GPUCommandEncoder>
    : <dfn>copyBufferToTexture(source, destination, copySize)</dfn>
    ::
        Encode a command into the {{GPUCommandEncoder}} that copies data from a sub-region of a
        {{GPUBuffer}} to a sub-region of one or multiple continuous {{GPUTexture}} [=subresources=].

        <div algorithm=GPUCommandEncoder.copyBufferToTexture>
            **Called on:** {{GPUCommandEncoder}} |this|.

            **Arguments:**
            <pre class=argumentdef for="GPUCommandEncoder/copyBufferToTexture(source, destination, copySize)">
                |source|: Combined with |copySize|, defines the region of the source buffer.
                |destination|: Combined with |copySize|, defines the region of the destination
                    texture [=subresource=].
                |copySize|:
            </pre>

            **Returns:** `void`

            If any of the following conditions are unsatisfied, generate a validation error and stop.
            <div class=validusage>
                - |this|.{{GPUCommandEncoder/[[state]]}} is {{encoder state/open}}.
                - [$validating GPUBufferCopyView$](|source|) returns `true`.
                - |source|.{{GPUBufferCopyView/buffer}}.{{GPUBuffer/[[usage]]}} contains
                    {{GPUBufferUsage/COPY_SRC}}.
                - [$validating GPUTextureCopyView$](|destination|) returns `true`.
                - |destination|.{{GPUTextureCopyView/texture}}.{{GPUTexture/[[textureUsage]]}} contains
                    {{GPUTextureUsage/COPY_DST}}.
                - |destination|.{{GPUTextureCopyView/texture}}.{{GPUTexture/[[sampleCount]]}} is 1.
                - [$validating linear texture data$](|source|,
                    |source|.{{GPUBufferCopyView/buffer}}.{{GPUBuffer/[[size]]}},
                    |destination|.{{GPUTextureCopyView/texture}}.{{GPUTexture/[[format]]}},
                    |copySize|) succeeds.
                - [=Valid Texture Copy Range=] applies to |destination| and |copySize|.
            </div>
        </div>

    : <dfn>copyTextureToBuffer(source, destination, copySize)</dfn>
    ::
        Encode a command into the {{GPUCommandEncoder}} that copies data from a sub-region of one or
        multiple continuous {{GPUTexture}} [=subresources=]to a sub-region of a {{GPUBuffer}}.

        <div algorithm=GPUCommandEncoder.copyTextureToBuffer>
            **Called on:** {{GPUCommandEncoder}} |this|.

            **Arguments:**
            <pre class=argumentdef for="GPUCommandEncoder/copyTextureToBuffer(source, destination, copySize)">
                |source|: Combined with |copySize|, defines the region of the source texture [=subresources=].
                |destination|: Combined with |copySize|, defines the region of the destination buffer.
                |copySize|:
            </pre>

            **Returns:** `void`

            If any of the following conditions are unsatisfied, generate a validation error and stop.
            <div class=validusage>
                - |this|.{{GPUCommandEncoder/[[state]]}} is {{encoder state/open}}.
                - [$validating GPUTextureCopyView$](|source|) returns true.
                - |source|.{{GPUTextureCopyView/texture}}.{{GPUTexture/[[textureUsage]]}} contains
                    {{GPUTextureUsage/COPY_SRC}}.
                - |source|.{{GPUTextureCopyView/texture}}.{{GPUTexture/[[sampleCount]]}} is 1.
                - [$validating GPUBufferCopyView$](|destination|) returns true.
                - |destination|.{{GPUBufferCopyView/buffer}}.{{GPUBuffer/[[usage]]}} contains
                    {{GPUBufferUsage/COPY_DST}}.
                - [$validating linear texture data$](|destination|,
                    |destination|.{{GPUBufferCopyView/buffer}}.{{GPUBuffer/[[size]]}},
                    |source|.{{GPUTextureCopyView/texture}}.{{GPUTexture/[[format]]}},
                    |copySize|) succeeds.
                - [=Valid Texture Copy Range=] applies to |source| and |copySize|.
            </div>
        </div>

    : <dfn>copyTextureToTexture(source, destination, copySize)</dfn>
    ::
        Encode a command into the {{GPUCommandEncoder}} that copies data from a sub-region of one
        or multiple contiguous {{GPUTexture}} [=subresources=] to another sub-region of one or
        multiple continuous {{GPUTexture}} [=subresources=].

        <div algorithm=GPUCommandEncoder.copyTextureToTexture>
            **Called on:** {{GPUCommandEncoder}} |this|.

            **Arguments:**
            <pre class=argumentdef for="GPUCommandEncoder/copyTextureToTexture(source, destination, copySize)">
                |source|: Combined with |copySize|, defines the region of the source texture [=subresources=].
                |destination|: Combined with |copySize|, defines the region of the destination
                    texture [=subresources=].
                |copySize|:
            </pre>

            **Returns:** `void`

            1. Let |copy of the whole subresource| be the command |this|.{{GPUCommandEncoder/copyTextureToTexture()}}
                whose parameters |source|, |destination| and |copySize| meet the following conditions:
                - The [=textureCopyView subresource size=] of |source| is equal to |copySize|.
                - The [=textureCopyView subresource size=] of |destination| is equal to |copySize|.
            1. If any of the following conditions are unsatisfied, generate a validation error and stop.
                <div class=validusage>
                    - |this|.{{GPUCommandEncoder/[[state]]}} is {{encoder state/open}}.
                    - [$validating GPUTextureCopyView$](|source|) returns true.
                    - |source|.{{GPUTextureCopyView/texture}}.{{GPUTexture/[[textureUsage]]}} contains
                        {{GPUTextureUsage/COPY_SRC}}.
                    - [$validating GPUTextureCopyView$](|destination|) returns true.
                    - |destination|.{{GPUTextureCopyView/texture}}.{{GPUTexture/[[textureUsage]]}} contains
                        {{GPUTextureUsage/COPY_DST}}.
                    - |source|.{{GPUTextureCopyView/texture}}.{{GPUTexture/[[sampleCount]]}} is equal to |destination|.
                        {{GPUTextureCopyView/texture}}.{{GPUTexture/[[sampleCount]]}}.
                    - If |source|.{{GPUTextureCopyView/texture}}.{{GPUTexture/[[sampleCount]]}} is greater than 1:
                        - The copy with |source|, |destination| and |copySize| is a |copy of the whole subresource|.
                    - |source|.{{GPUTextureCopyView/texture}}.{{GPUTexture/[[format]]}} is equal to |destination|.
                        {{GPUTextureCopyView/texture}}.{{GPUTexture/[[format]]}}.
                    - If |source|.{{GPUTextureCopyView/texture}}.{{GPUTexture/[[format]]}} is a depth-stencil format:
                        - The copy with |source|, |destination| and |copySize| is a |copy of the whole subresource|.
                    - [=Valid Texture Copy Range=] applies to |source| and |copySize|.
                    - [=Valid Texture Copy Range=] applies to |destination| and |copySize|.
                    - The [$set of subresources for texture copy$](|source|, |copySize|) and
                        the [$set of subresources for texture copy$](|destination|, |copySize|) is disjoint.
                </div>
        </div>
</dl>

<div algorithm>
    The <dfn abstract-op>set of subresources for texture copy</dfn>(|textureCopyView|, |copySize|)
    is the set containing:

      - If |textureCopyView|.{{GPUTextureCopyView/texture}}.{{GPUTexture/[[dimension]]}}
        is {{GPUTextureDimension/"2d"}}:
          - For each |arrayLayer| of the |copySize|.[=Extent3D/depth=] [=array layers=]
            starting at |textureCopyView|.{{GPUTextureCopyView/origin}}.[=Origin3D/z=]:
              - The [=subresource=] of |textureCopyView|.{{GPUTextureCopyView/texture}} at
                [=mipmap level=] |textureCopyView|.{{GPUTextureCopyView/mipLevel}} and
                [=array layer=] |arrayLayer|.
      - Otherwise:
          - The [=subresource=] of |textureCopyView|.{{GPUTextureCopyView/texture}} at
            [=mipmap level=] |textureCopyView|.{{GPUTextureCopyView/mipLevel}}.
</div>

## Debug Markers ## {#command-encoder-debug-markers}

Both command encoders and programmable pass encoders provide methods to apply debug labels to groups
of commands or insert a single label into the command sequence. Debug groups can be nested to create
a hierarchy of labeled commands. These labels may be passed to the native API backends for tooling,
may be used by the user agent's internal tooling, or may be a no-op when such tooling is not
available or applicable.

Debug groups in a {{GPUCommandEncoder}} or {{GPUProgrammablePassEncoder}}
must be well nested.

<dl dfn-type=method dfn-for=GPUCommandEncoder>
    : <dfn>pushDebugGroup(groupLabel)</dfn>
    ::

        Marks the beginning of a labeled group of commands for the {{GPUCommandEncoder}}.

        <div algorithm=GPUCommandEncoder.pushDebugGroup>
            **Called on:** {{GPUCommandEncoder}} |this|.

            **Arguments:**
            <pre class=argumentdef for="GPUCommandEncoder/pushDebugGroup(groupLabel)">
                |groupLabel|: The label for the command group.
            </pre>

            **Returns:** void

            Issue the following steps on the [=Device timeline=] of |this|:
            <div class=device-timeline>
                - If any of the following conditions are unsatisfied, make |this| [=invalid=] and stop.
                    <div class=validusage>
                        - |this|.{{GPUCommandEncoder/[[state]]}} is {{encoder state/open}}.
                    </div>
                - Push |groupLabel| onto then end of |this|.{{GPUCommandEncoder/[[debug_group_stack]]}}.
            </div>
        </div>

    : <dfn>popDebugGroup()</dfn>
    ::

        Marks the end of a labeled group of commands for the {{GPUCommandEncoder}}.

        <div algorithm=GPUCommandEncoder.popDebugGroup>
            **Called on:** {{GPUCommandEncoder}} |this|.

            **Returns:** void

            Issue the following steps on the [=Device timeline=] of |this|:
            <div class=device-timeline>
                - If any of the following conditions are unsatisfied, make |this| [=invalid=] and stop.
                    <div class=validusage>
                        - |this|.{{GPUCommandEncoder/[[state]]}} is {{encoder state/open}}.
                        - |this|.{{GPUCommandEncoder/[[debug_group_stack]]}}.length is greater than 0.
                    </div>
                - Pop an entry off the end of |this|.{{GPUCommandEncoder/[[debug_group_stack]]}}.
            </div>
        </div>

    : <dfn>insertDebugMarker(markerLabel)</dfn>
    ::

        Marks the end of a labeled group of commands for the {{GPUCommandEncoder}}.

        <div algorithm=GPUCommandEncoder.insertDebugMarker>
            **Called on:** {{GPUCommandEncoder}} |this|.

            **Arguments:**
            <pre class=argumentdef for="GPUCommandEncoder/insertDebugMarker(markerLabel)">
                markerLabel: The label to insert.
            </pre>

            **Returns:** void

            Issue the following steps on the [=Device timeline=] of |this|:
            <div class=device-timeline>
                - If any of the following conditions are unsatisfied, make |this| [=invalid=] and stop.
                    <div class=validusage>
                        - |this|.{{GPUCommandEncoder/[[state]]}} is {{encoder state/open}}.
                    </div>
            </div>
        </div>
</dl>

## Queries ## {#command-encoder-queries}

<dl dfn-type=method dfn-for=GPUCommandEncoder>
    : <dfn>writeTimestamp(querySet, queryIndex)</dfn>
    ::

        <div algorithm=GPUCommandEncoder.writeTimestamp>
            **Called on:** {{GPUCommandEncoder}} this.

            **Arguments:**
            <pre class=argumentdef for="GPUCommandEncoder/writeTimestamp(querySet, queryIndex)">
                querySet:
                queryIndex:
            </pre>

            **Returns:** void

            Issue: Describe {{GPUCommandEncoder/writeTimestamp()}} algorithm steps.
        </div>

    : <dfn>resolveQuerySet(querySet, firstQuery, queryCount, destination, destinationOffset)</dfn>
    ::

        <div algorithm=GPUCommandEncoder.resolveQuerySet>
            **Called on:** {{GPUCommandEncoder}} this.

            **Arguments:**
            <pre class=argumentdef for="GPUCommandEncoder/resolveQuerySet(querySet, firstQuery, queryCount, destination, destinationOffset)">
                querySet:
                firstQuery:
                queryCount:
                destination:
                destinationOffset:
            </pre>

            **Returns:** void

            Issue: Describe {{GPUCommandEncoder/resolveQuerySet()}} algorithm steps.
        </div>
</dl>

## Finalization ## {#command-encoder-finalization}

A {{GPUCommandBuffer}} containing the commands recorded by the {{GPUCommandEncoder}} can be created
by calling {{GPUCommandEncoder/finish()}}. Once {{GPUCommandEncoder/finish()}} has been called the
command encoder can no longer be used.

<dl dfn-type=method dfn-for=GPUCommandEncoder>
    : <dfn>finish(descriptor)</dfn>
    ::

        Completes recording of the commands sequence and returns a corresponding {{GPUCommandBuffer}}.

        <div algorithm=GPUCommandEncoder.finish>
            **Called on:** {{GPUCommandEncoder}} |this|.

            **Arguments:**
            <pre class=argumentdef for="GPUCommandEncoder/finish(descriptor)">
                descriptor:
            </pre>

            **Returns:** void

            Issue the following steps on the [=Device timeline=] of |this|:
            <div class=device-timeline>
                1. If any of the following conditions are unsatisfied, generate a validation
                    error and stop.
                    <div class=validusage>
                        - |this| is [=valid=].
                        - |this|.{{GPUCommandEncoder/[[debug_group_stack]]}}.length is 0.
                    </div>

                Issue: Add remaining validation.
            </div>
        </div>
</dl>

# Programmable Passes # {#programmable-passes}

<script type=idl>

interface mixin GPUProgrammablePassEncoder {
    void setBindGroup(GPUIndex32 index, GPUBindGroup bindGroup,
                      optional sequence<GPUBufferDynamicOffset> dynamicOffsets = []);

    void setBindGroup(GPUIndex32 index, GPUBindGroup bindGroup,
                      Uint32Array dynamicOffsetsData,
                      GPUSize64 dynamicOffsetsDataStart,
                      GPUSize32 dynamicOffsetsDataLength);

    void pushDebugGroup(USVString groupLabel);
    void popDebugGroup();
    void insertDebugMarker(USVString markerLabel);
};
</script>

  - One offset must be passed to
      {{GPUProgrammablePassEncoder/setBindGroup(index, bindGroup, dynamicOffsets)}} or
      {{GPUProgrammablePassEncoder/setBindGroup(index, bindGroup, dynamicOffsetsData, dynamicOffsetsDataStart, dynamicOffsetsDataLength)}}
      for each dynamic binding in a bind group, in increasing order of
      {{GPUBindGroupLayoutEntry/binding}} number.

{{GPUProgrammablePassEncoder}} has the following internal slots:

<dl dfn-type=attribute dfn-for="GPUProgrammablePassEncoder">
    : <dfn>\[[debug_group_stack]]</dfn> of type `sequence<USVString>`.
    ::
        A stack of active debug group labels.

    : <dfn>\[[bind_groups]]</dfn>, of type map&lt;index, {{GPUBindGroup}}&gt;
    ::
        The current {{GPUBindGroup}} for each index, initially empty.
</dl>

## Bind Groups ## {#programmable-passes-bind-groups}

<dl dfn-type=method dfn-for=GPUProgrammablePassEncoder>
    : <dfn>setBindGroup(index, bindGroup, dynamicOffsets)</dfn>
    ::

        <div algorithm=GPUProgrammablePassEncoder.setBindGroup>
            **Called on:** {{GPUProgrammablePassEncoder}} this.

            **Arguments:**
            <pre class=argumentdef for="GPUProgrammablePassEncoder/setBindGroup(index, bindGroup, dynamicOffsets)">
                |index|: The index to set the bind group at.
                |bindGroup|: Bind group to use for subsequent render or compute commands.

                <!--The overload appears to be confusing bikeshed, and it ends up expecting this to
                define the arguments for the 5-arg variant of the method, despite the "for"
                explicitly pointing at the 3-arg variant.-->
                <!--|dynamicOffsets|: Array containing buffer offsets in bytes for each entry in
                    |bindGroup| with marked as {{GPUBindGroupLayoutEntry/hasDynamicOffset}}.-->
            </pre>

            Issue: Resolve bikeshed conflict when using `argumentdef` with overloaded functions that prevents us from
                defining |dynamicOffsets|.

            **Returns:** void

            Issue the following steps on the [=Device timeline=] of |this|.{{GPUObjectBase/[[device]]}}:
            <div class=device-timeline>
                1. If any of the following conditions are unsatisfied, make |this| [=invalid=] and stop.
                    <div class=validusage>
                        - |bindGroup| is [$valid to use with$] |this|.
                        - |index| &lt; {{GPULimits/maxBindGroups|GPULimits.maxBindGroups}}.
                        - |dynamicOffsets|.length is
                            |bindGroup|.{{GPUBindGroup/[[layout]]}}.{{GPUBindGroupLayout/[[dynamicOffsetCount]]}}.

                        - [$Iterate over each dynamic binding offset$] in |bindGroup| and
                            run the following steps for each |bufferBinding|, |minBufferBindingSize|,
                            and |dynamicOffsetIndex|:

                            - Let |bufferDynamicOffset| be |dynamicOffsets|[|dynamicOffsetIndex|].
                            - |bufferBinding|.{{GPUBufferBinding/offset}} + |bufferDynamicOffset| +
                                |minBufferBindingSize| &le;
                                |bufferBinding|.{{GPUBufferBinding/buffer}}.{{GPUBuffer/[[size]]}}.
                    </div>
                1. Set |this|.{{GPUProgrammablePassEncoder/[[bind_groups]]}}[|index|] to be |bindGroup|.
            </div>
        </div>

    : <dfn>setBindGroup(index, bindGroup, dynamicOffsetsData, dynamicOffsetsDataStart, dynamicOffsetsDataLength)</dfn>
    ::

        <div algorithm=GPUProgrammablePassEncoder.setBindGroup2>
            **Called on:** {{GPUProgrammablePassEncoder}} this.

            **Arguments:**
            <pre class=argumentdef for="GPUProgrammablePassEncoder/setBindGroup(index, bindGroup, dynamicOffsetsData, dynamicOffsetsDataStart, dynamicOffsetsDataLength)">
                |index|: The index to set the bind group at.
                |bindGroup|: Bind group to use for subsequent render or compute commands.
                |dynamicOffsetsData|: Array containing buffer offsets in bytes for each entry in
                    |bindGroup| with marked as {{GPUBindGroupLayoutEntry/hasDynamicOffset}}.
                |dynamicOffsetsDataStart|: Offset in elements into |dynamicOffsetsData| where the
                    buffer offset data begins.
                |dynamicOffsetsDataLength|: Number of buffer offsets to read from |dynamicOffsetsData|.
            </pre>

            **Returns:** void

            Issue the following steps on the [=Device timeline=] of |this|.{{GPUObjectBase/[[device]]}}:
            <div class=device-timeline>
                1. If any of the following conditions are unsatisfied, make |this| [=invalid=] and stop.
                    <div class=validusage>
                        - |bindGroup| is [$valid to use with$] |this|.
                        - |index| &lt; {{GPULimits/maxBindGroups|GPULimits.maxBindGroups}}.
                        - |dynamicOffsetsDataLength| is
                            |bindGroup|.{{GPUBindGroup/[[layout]]}}.{{GPUBindGroupLayout/[[dynamicOffsetCount]]}}.
                        - |dynamicOffsetsDataStart| + |dynamicOffsetsDataLength| &le; |dynamicOffsetsData|.length.

                        - [$Iterate over each dynamic binding offset$] in |bindGroup| and
                            run the following steps for each |bufferBinding|, |minBufferBindingSize|,
                            and |dynamicOffsetIndex|:

                            - Let |bufferDynamicOffset| be
                                |dynamicOffsetsData|[|dynamicOffsetIndex| + |dynamicOffsetsDataStart|].
                            - |bufferBinding|.{{GPUBufferBinding/offset}} + |bufferDynamicOffset| +
                                |minBufferBindingSize| &le;
                                |bufferBinding|.{{GPUBufferBinding/buffer}}.{{GPUBuffer/[[size]]}}.
                    </div>
                1. Set |this|.{{GPUProgrammablePassEncoder/[[bind_groups]]}}[|index|] to be |bindGroup|.
            </div>
        </div>
</dl>

<div algorithm>
    To <dfn abstract-op>Iterate over each dynamic binding offset</dfn> in a given {{GPUBindGroup}} |bindGroup|
    with a given list of |steps| to be executed for each dynamic offset:

    1. Let |dynamicOffsetIndex| be `0`.
    1. Let |layout| be |bindGroup|.{{GPUBindGroup/[[layout]]}}.
    1. For each {{GPUBindGroupEntry}} |entry| in |bindGroup|.{{GPUBindGroup/[[entries]]}}:
        1. Let |bindingDescriptor| be the {{GPUBindGroupLayoutEntry}} at
            |layout|.{{GPUBindGroupLayout/[[entryMap]]}}[|entry|.{{GPUBindGroupEntry/binding}}]:
        1. If |bindingDescriptor|.{{GPUBindGroupLayoutEntry/hasDynamicOffset}} is `true`:
            1. Let |bufferBinding| be |entry|.{{GPUBindGroupEntry/resource}}.
            1. Let |minBufferBindingSize| be |bindingDescriptor|.{{GPUBindGroupLayoutEntry/minBufferBindingSize}}.
            1. Call |steps| with |bufferBinding|, |minBufferBindingSize|, and |dynamicOffsetIndex|.
            1. Let |dynamicOffsetIndex| be |dynamicOffsetIndex| + `1`
</div>

## Debug Markers ## {#programmable-passes-debug-markers}

Debug marker methods for programmable pass encoders provide the same functionality as
[[#command-encoder-debug-markers|command encoder debug markers]] while recording a programmable
pass.

<dl dfn-type=method dfn-for=GPUProgrammablePassEncoder>
    : <dfn>pushDebugGroup(groupLabel)</dfn>
    ::

        Marks the beginning of a labeled group of commands for the {{GPUProgrammablePassEncoder}}.

        <div algorithm=GPUProgrammablePassEncoder.pushDebugGroup>
            **Called on:** {{GPUProgrammablePassEncoder}} |this|.

            **Arguments:**
            <pre class=argumentdef for="GPUProgrammablePassEncoder/pushDebugGroup(groupLabel)">
                |groupLabel|: The label for the command group.
            </pre>

            **Returns:** void

            Issue the following steps on the [=Device timeline=] of |this|:
            <div class=device-timeline>
                1. Push |groupLabel| onto then end of |this|.{{GPUProgrammablePassEncoder/[[debug_group_stack]]}}.
            </div>
        </div>

    : <dfn>popDebugGroup()</dfn>
    ::

        Marks the end of a labeled group of commands for the {{GPUProgrammablePassEncoder}}.

        <div algorithm=GPUProgrammablePassEncoder.popDebugGroup>
            **Called on:** {{GPUProgrammablePassEncoder}} |this|.

            **Returns:** void

            Issue the following steps on the [=Device timeline=] of |this|:
            <div class=device-timeline>
                1. If any of the following conditions are unsatisfied, generate a validation
                    error and stop.
                    <div class=validusage>
                        - |this|.{{GPUProgrammablePassEncoder/[[debug_group_stack]]}}.length is greater than 0.
                    </div>
                1. Pop an entry off the end of |this|.{{GPUProgrammablePassEncoder/[[debug_group_stack]]}}.
            </div>
        </div>

    : <dfn>insertDebugMarker(markerLabel)</dfn>
    ::

        Inserts a single debug marker label into the {{GPUProgrammablePassEncoder}}'s commands sequence.

        <div algorithm=GPUProgrammablePassEncoder.insertDebugMarker>
            **Called on:** {{GPUProgrammablePassEncoder}} this.

            **Arguments:**
            <pre class=argumentdef for="GPUProgrammablePassEncoder/insertDebugMarker(markerLabel)">
                markerLabel: The label to insert.
            </pre>

            **Returns:** void
        </div>
</dl>

# Compute Passes # {#compute-passes}

## GPUComputePassEncoder ## {#compute-pass-encoder}

<script type=idl>
interface GPUComputePassEncoder {
    void setPipeline(GPUComputePipeline pipeline);
    void dispatch(GPUSize32 x, optional GPUSize32 y = 1, optional GPUSize32 z = 1);
    void dispatchIndirect(GPUBuffer indirectBuffer, GPUSize64 indirectOffset);

    void beginPipelineStatisticsQuery(GPUQuerySet querySet, GPUSize32 queryIndex);
    void endPipelineStatisticsQuery();

    void writeTimestamp(GPUQuerySet querySet, GPUSize32 queryIndex);

    void endPass();
};
GPUComputePassEncoder includes GPUObjectBase;
GPUComputePassEncoder includes GPUProgrammablePassEncoder;
</script>

### Creation ### {#compute-pass-encoder-creation}

<script type=idl>
dictionary GPUComputePassDescriptor : GPUObjectDescriptorBase {
};
</script>

### Dispatch ### {#compute-pass-encoder-dispatch}

<dl dfn-type=method dfn-for=GPUComputePassEncoder>
    : <dfn>setPipeline(pipeline)</dfn>
    ::

        <div algorithm="GPUComputePassEncoder.setPipeline">
            **Called on:** {{GPUComputePassEncoder}} this.

            **Arguments:**
            <pre class=argumentdef for="GPUComputePassEncoder/setPipeline(pipeline)">
                pipeline:
            </pre>

            **Returns:** void

            Issue: Describe {{GPUComputePassEncoder/setPipeline()}} algorithm steps.
        </div>

    : <dfn>dispatch(x, y, z)</dfn>
    ::

        <div algorithm="GPUComputePassEncoder.dispatch">
            **Called on:** {{GPUComputePassEncoder}} this.

            **Arguments:**
            <pre class=argumentdef for="GPUComputePassEncoder/dispatch(x, y, z)">
                x:
                y:
                z:
            </pre>

            **Returns:** void

            Issue: Describe {{GPUComputePassEncoder/dispatch()}} algorithm steps.
        </div>

    : <dfn>dispatchIndirect(indirectBuffer, indirectOffset)</dfn>
    ::

        <div algorithm="GPUComputePassEncoder.dispatchIndirect">
            **Called on:** {{GPUComputePassEncoder}} this.

            **Arguments:**
            <pre class=argumentdef for="GPUComputePassEncoder/dispatchIndirect(indirectBuffer, indirectOffset)">
                indirectBuffer:
                indirectOffset:
            </pre>

            **Returns:** void

            Issue: Describe {{GPUComputePassEncoder/dispatchIndirect()}} algorithm steps.
        </div>
</dl>

### Queries ### {#compute-pass-encoder-queries}

<dl dfn-type=method dfn-for=GPUComputePassEncoder>
    : <dfn>beginPipelineStatisticsQuery(querySet, queryIndex)</dfn>
    ::

        <div algorithm="GPUComputePassEncoder.beginPipelineStatisticsQuery">
            **Called on:** {{GPUComputePassEncoder}} this.

            **Arguments:**
            <pre class=argumentdef for="GPUComputePassEncoder/beginPipelineStatisticsQuery(querySet, queryIndex)">
                querySet:
                queryIndex:
            </pre>

            **Returns:** void

            Issue: Describe {{GPUComputePassEncoder/beginPipelineStatisticsQuery()}} algorithm steps.
        </div>

    : <dfn>endPipelineStatisticsQuery()</dfn>
    ::

        <div algorithm="GPUComputePassEncoder.endPipelineStatisticsQuery">
            **Called on:** {{GPUComputePassEncoder}} this.

            **Returns:** void

            Issue: Describe {{GPUComputePassEncoder/endPipelineStatisticsQuery()}} algorithm steps.
        </div>

    : <dfn>writeTimestamp(querySet, queryIndex)</dfn>
    ::

        <div algorithm="GPUComputePassEncoder.writeTimestamp">
            **Called on:** {{GPUComputePassEncoder}} this.

            **Arguments:**
            <pre class=argumentdef for="GPUComputePassEncoder/writeTimestamp(querySet, queryIndex)">
                querySet:
                queryIndex:
            </pre>

            **Returns:** void

            Issue: Describe {{GPUComputePassEncoder/writeTimestamp()}} algorithm steps.
        </div>
</dl>

### Finalization ### {#compute-pass-encoder-finalization}

The compute pass encoder can be ended by calling {{GPUComputePassEncoder/endPass()}} once the user
has finished recording commands for the pass. Once {{GPUComputePassEncoder/endPass()}} has been
called the compute pass encoder can no longer be used.

<dl dfn-type=method dfn-for=GPUComputePassEncoder>
    : <dfn>endPass()</dfn>
    ::

        Completes recording of the compute pass commands sequence.

        <div algorithm="GPUComputePassEncoder.endPass">
            **Called on:** {{GPUComputePassEncoder}} |this|.

            **Returns:** void

            Issue the following steps on the [=Device timeline=] of |this|:
            <div class=device-timeline>
                1. If any of the following conditions are unsatisfied, generate a validation
                    error and stop.
                    <div class=validusage>
                        - |this|.{{GPUProgrammablePassEncoder/[[debug_group_stack]]}}.length is 0.
                    </div>

                Issue: Add remaining validation.
            </div>

            Issue: Allowed for GPUs to use fixed point or rounded viewport coordinates
        </div>
</dl>

# Render Passes # {#render-passes}

## GPURenderPassEncoder ## {#render-pass-encoder}

<script type=idl>
interface mixin GPURenderEncoderBase {
    void setPipeline(GPURenderPipeline pipeline);

    void setIndexBuffer(GPUBuffer buffer, GPUIndexFormat indexFormat, optional GPUSize64 offset = 0, optional GPUSize64 size = 0);
    void setVertexBuffer(GPUIndex32 slot, GPUBuffer buffer, optional GPUSize64 offset = 0, optional GPUSize64 size = 0);

    void draw(GPUSize32 vertexCount, optional GPUSize32 instanceCount = 1,
              optional GPUSize32 firstVertex = 0, optional GPUSize32 firstInstance = 0);
    void drawIndexed(GPUSize32 indexCount, optional GPUSize32 instanceCount = 1,
                     optional GPUSize32 firstIndex = 0,
                     optional GPUSignedOffset32 baseVertex = 0,
                     optional GPUSize32 firstInstance = 0);

    void drawIndirect(GPUBuffer indirectBuffer, GPUSize64 indirectOffset);
    void drawIndexedIndirect(GPUBuffer indirectBuffer, GPUSize64 indirectOffset);
};

interface GPURenderPassEncoder {
    void setViewport(float x, float y,
                     float width, float height,
                     float minDepth, float maxDepth);

    void setScissorRect(GPUIntegerCoordinate x, GPUIntegerCoordinate y,
                        GPUIntegerCoordinate width, GPUIntegerCoordinate height);

    void setBlendColor(GPUColor color);
    void setStencilReference(GPUStencilValue reference);

    void beginOcclusionQuery(GPUSize32 queryIndex);
    void endOcclusionQuery();

    void beginPipelineStatisticsQuery(GPUQuerySet querySet, GPUSize32 queryIndex);
    void endPipelineStatisticsQuery();

    void writeTimestamp(GPUQuerySet querySet, GPUSize32 queryIndex);

    void executeBundles(sequence<GPURenderBundle> bundles);
    void endPass();
};
GPURenderPassEncoder includes GPUObjectBase;
GPURenderPassEncoder includes GPUProgrammablePassEncoder;
GPURenderPassEncoder includes GPURenderEncoderBase;
</script>

  * In indirect draw calls, the base instance field (inside the indirect
    buffer data) must be set to zero.

{{GPURenderEncoderBase}} has the following internal slots:

<dl dfn-type=attribute dfn-for="GPURenderEncoderBase">
    : <dfn>\[[pipeline]]</dfn>, of type {{GPURenderPipeline}}
    ::
        The current {{GPURenderPipeline}}, initially `null`.

    : <dfn>\[[index_buffer]]</dfn>, of type {{GPUBuffer}}
    ::
        The current buffer to read index data from, initially `null`.

    : <dfn>\[[index_format]]</dfn>, of type {{GPUIndexFormat}}
    ::
        The format of the index data in {{GPURenderEncoderBase/[[index_buffer]]}}.

    : <dfn>\[[vertex_buffers]]</dfn>, of type map&lt;slot, {{GPUBuffer}}&gt;
    ::
        The current {{GPUBuffer}}s to read vertex data from for each slot, initially empty.
</dl>

{{GPURenderPassEncoder}} has the following internal slots:

<dl dfn-type=attribute dfn-for="GPURenderPassEncoder">
    : <dfn>\[[attachment_size]]</dfn>
    ::
        Set to the following extents:
            - `width, height` = the dimensions of the pass's render attachments
</dl>

When a {{GPURenderPassEncoder}} is created, it has the following default state:
  * Viewport:
      * `x, y` = `0.0, 0.0`
      * `width, height` = the dimensions of the pass's render targets
      * `minDepth, maxDepth` = `0.0, 1.0`
  * Scissor rectangle:
      * `x, y` = `0, 0`
      * `width, height` = the dimensions of the pass's render targets

When a {{GPURenderBundle}} is executed, it does not inherit the pass's pipeline,
bind groups, or vertex or index buffers. After a {{GPURenderBundle}} has executed,
the pass's pipeline, bind groups, and vertex and index buffers are cleared. If zero
{{GPURenderBundle}}s are executed, the command buffer state is unchanged.

### Creation ### {#render-pass-encoder-creation}

<script type=idl>
dictionary GPURenderPassDescriptor : GPUObjectDescriptorBase {
    required sequence<GPURenderPassColorAttachmentDescriptor> colorAttachments;
    GPURenderPassDepthStencilAttachmentDescriptor depthStencilAttachment;
    GPUQuerySet occlusionQuerySet;
};
</script>

<dl dfn-type=dict-member dfn-for=GPURenderPassDescriptor>
    : <dfn>colorAttachments</dfn>
    ::
        The set of {{GPURenderPassColorAttachmentDescriptor}} values in this sequence defines which
        color attachments will be output to when executing this render pass.

    : <dfn>depthStencilAttachment</dfn>
    ::
        The {{GPURenderPassDepthStencilAttachmentDescriptor}} value that defines the depth/stencil
        attachment that will be output to and tested against when executing this render pass.

    : <dfn>occlusionQuerySet</dfn>
    ::
        Issue: Describe this dictionary member
</dl>

<div class=validusage dfn-for=GPURenderPassDescriptor>
    <dfn abstract-op>GPURenderPassDescriptor Valid Usage</dfn>

    Given a {{GPURenderPassDescriptor}} |this| the following validation rules apply:

    1. |this|.{{GPURenderPassDescriptor/colorAttachments}}.length must be less than or equal to the
        [=maximum color attachments=].
    1. |this|.{{GPURenderPassDescriptor/colorAttachments}}.length must greater than `0` or
        |this|.{{GPURenderPassDescriptor/depthStencilAttachment}} must not be `null`.
    1. For each |colorAttachment| in |this|.{{GPURenderPassDescriptor/colorAttachments}}:

        1. |colorAttachment| must meet the [$GPURenderPassColorAttachmentDescriptor/GPURenderPassColorAttachmentDescriptor Valid Usage$] rules.

    1. If |this|.{{GPURenderPassDescriptor/depthStencilAttachment}} is not `null`:

        1. |this|.{{GPURenderPassDescriptor/depthStencilAttachment}} must meet the [$GPURenderPassDepthStencilAttachmentDescriptor/GPURenderPassDepthStencilAttachmentDescriptor Valid Usage$] rules.

    1. Each {{GPURenderPassColorAttachmentDescriptor/attachment}} in |this|.{{GPURenderPassDescriptor/colorAttachments}}
        and |this|.{{GPURenderPassDescriptor/depthStencilAttachment}}.{{GPURenderPassDepthStencilAttachmentDescriptor/attachment}},
        if present, must have all have the same {{GPUTexture/[[sampleCount]]}}.

    1. The dimensions of the [=subresource=]s seen by each {{GPURenderPassColorAttachmentDescriptor/attachment}} in |this|.{{GPURenderPassDescriptor/colorAttachments}}
        and |this|.{{GPURenderPassDescriptor/depthStencilAttachment}}.{{GPURenderPassDepthStencilAttachmentDescriptor/attachment}},
        if present, must match.

    Issue: Define <dfn for=>maximum color attachments</dfn>

    Issue(gpuweb/gpuweb#503): support for no attachments
</div>

#### Color Attachments #### {#color-attachments}

<script type=idl>
dictionary GPURenderPassColorAttachmentDescriptor {
    required GPUTextureView attachment;
    GPUTextureView resolveTarget;

    required (GPULoadOp or GPUColor) loadValue;
    GPUStoreOp storeOp = "store";
};
</script>

<dl dfn-type=dict-member dfn-for=GPURenderPassColorAttachmentDescriptor>
    : <dfn>attachment</dfn>
    ::
        A {{GPUTextureView}} describing the texture [=subresource=] that will be output to for this
        color attachment.

    : <dfn>resolveTarget</dfn>
    ::
        A {{GPUTextureView}} describing the texture [=subresource=] that will receive the resolved
        output for this color attachment if {{GPURenderPassColorAttachmentDescriptor/attachment}} is
        multisampled.

    : <dfn>loadValue</dfn>
    ::
        If a {{GPULoadOp}}, indicates the load operation to perform on
        {{GPURenderPassColorAttachmentDescriptor/attachment}} prior to executing the render pass.
        If a {{GPUColor}}, indicates the value to clear {{GPURenderPassColorAttachmentDescriptor/attachment}}
        to prior to executing the render pass.

    : <dfn>storeOp</dfn>
    ::
        The store operation to perform on {{GPURenderPassColorAttachmentDescriptor/attachment}}
        after executing the render pass.
</dl>

<div class=validusage dfn-for=GPURenderPassColorAttachmentDescriptor>
    <dfn abstract-op>GPURenderPassColorAttachmentDescriptor Valid Usage</dfn>

    Given a {{GPURenderPassColorAttachmentDescriptor}} |this| the following validation rules
    apply:

    1. |this|.{{GPURenderPassColorAttachmentDescriptor/attachment}} must have a renderable color format.
    1. |this|.{{GPURenderPassColorAttachmentDescriptor/attachment}}.{{GPUTextureView/[[texture]]}}.{{GPUTexture/[[textureUsage]]}}
        must contain {{GPUTextureUsage/OUTPUT_ATTACHMENT}}.
    1. |this|.{{GPURenderPassColorAttachmentDescriptor/attachment}} must be a view of a single [=subresource=].
    1. If |this|.{{GPURenderPassColorAttachmentDescriptor/resolveTarget}} is not `null`:

        1. |this|.{{GPURenderPassColorAttachmentDescriptor/attachment}} must be multisampled.
        1. |this|.{{GPURenderPassColorAttachmentDescriptor/resolveTarget}} must not be multisampled.
        1. |this|.{{GPURenderPassColorAttachmentDescriptor/resolveTarget}}.{{GPUTextureView/[[texture]]}}.{{GPUTexture/[[textureUsage]]}}
            must contain {{GPUTextureUsage/OUTPUT_ATTACHMENT}}.
        1. |this|.{{GPURenderPassColorAttachmentDescriptor/resolveTarget}} must be a view of a single [=subresource=].

        1. The dimensions of the [=subresource=]s seen by |this|.{{GPURenderPassColorAttachmentDescriptor/resolveTarget}}
            and |this|.{{GPURenderPassColorAttachmentDescriptor/attachment}} must match.
        1. |this|.{{GPURenderPassColorAttachmentDescriptor/resolveTarget}}.{{GPUTextureView/[[texture]]}}.{{GPUTexture/[[format]]}}
            must match |this|.{{GPURenderPassColorAttachmentDescriptor/attachment}}.{{GPUTextureView/[[texture]]}}.{{GPUTexture/[[format]]}}.
        1. Issue: Describe any remaining resolveTarget validation

    Issue: Describe the remaining validation rules for this type.
</div>

#### Depth/Stencil Attachments #### {#depth-stencil-attachments}

<script type=idl>
dictionary GPURenderPassDepthStencilAttachmentDescriptor {
    required GPUTextureView attachment;

    required (GPULoadOp or float) depthLoadValue;
    required GPUStoreOp depthStoreOp;
    boolean depthReadOnly = false;

    required (GPULoadOp or GPUStencilValue) stencilLoadValue;
    required GPUStoreOp stencilStoreOp;
    boolean stencilReadOnly = false;
};
</script>

<dl dfn-type=dict-member dfn-for=GPURenderPassDepthStencilAttachmentDescriptor>
    : <dfn>attachment</dfn>
    ::
        A {{GPUTextureView}} describing the texture [=subresource=] that will be output to
        and read from for this depth/stencil attachment.

    : <dfn>depthLoadValue</dfn>
    ::
        If a {{GPULoadOp}}, indicates the load operation to perform on
        {{GPURenderPassDepthStencilAttachmentDescriptor/attachment}}'s depth component prior to
        executing the render pass.
        If a `float`, indicates the value to clear {{GPURenderPassDepthStencilAttachmentDescriptor/attachment}}'s
        depth component to prior to executing the render pass.

    : <dfn>depthStoreOp</dfn>
    ::
        The store operation to perform on {{GPURenderPassDepthStencilAttachmentDescriptor/attachment}}'s
        depth component after executing the render pass.

    : <dfn>depthReadOnly</dfn>
    ::
        Indicates that the depth component of {{GPURenderPassDepthStencilAttachmentDescriptor/attachment}}
        is read only.

    : <dfn>stencilLoadValue</dfn>
    ::
        If a {{GPULoadOp}}, indicates the load operation to perform on
        {{GPURenderPassDepthStencilAttachmentDescriptor/attachment}}'s stencil component prior to
        executing the render pass.
        If a {{GPUStencilValue}}, indicates the value to clear
        {{GPURenderPassDepthStencilAttachmentDescriptor/attachment}}'s stencil component to prior to
        executing the render pass.

    : <dfn>stencilStoreOp</dfn>
    ::
        The store operation to perform on {{GPURenderPassDepthStencilAttachmentDescriptor/attachment}}'s
        stencil component after executing the render pass.

    : <dfn>stencilReadOnly</dfn>
    ::
        Indicates that the stencil component of {{GPURenderPassDepthStencilAttachmentDescriptor/attachment}}
        is read only.
</dl>

<div class=validusage dfn-for=GPURenderPassDepthStencilAttachmentDescriptor>
    <dfn abstract-op>GPURenderPassDepthStencilAttachmentDescriptor Valid Usage</dfn>

    Given a {{GPURenderPassDepthStencilAttachmentDescriptor}} |this| the following validation
    rules apply:

    1. |this|.{{GPURenderPassDepthStencilAttachmentDescriptor/attachment}} must have a renderable
        depth-and/or-stencil format.
    1. |this|.{{GPURenderPassDepthStencilAttachmentDescriptor/attachment}} must be a view of a
        single [=subresource=].
    1. |this|.{{GPURenderPassDepthStencilAttachmentDescriptor/attachment}}.{{GPUTexture/[[textureUsage]]}}
        must contain {{GPUTextureUsage/OUTPUT_ATTACHMENT}}.
    1. |this|.{{GPURenderPassDepthStencilAttachmentDescriptor/depthReadOnly}} is `true`,
        |this|.{{GPURenderPassDepthStencilAttachmentDescriptor/depthLoadValue}} must be
        {{GPULoadOp/"load"}} and |this|.{{GPURenderPassDepthStencilAttachmentDescriptor/depthStoreOp}}
        must be {{GPUStoreOp/"store"}}.
    1. |this|.{{GPURenderPassDepthStencilAttachmentDescriptor/stencilReadOnly}} is `true`,
        |this|.{{GPURenderPassDepthStencilAttachmentDescriptor/stencilLoadValue}} must be
        {{GPULoadOp/"load"}} and |this|.{{GPURenderPassDepthStencilAttachmentDescriptor/stencilStoreOp}}
        must be {{GPUStoreOp/"store"}}.

    Issue: Describe the remaining validation rules for this type.
</div>

#### Load &amp; Store Operations #### {#load-and-store-ops}

<script type=idl>
enum GPULoadOp {
    "load"
};
</script>

<script type=idl>
enum GPUStoreOp {
    "store",
    "clear"
};
</script>

### Drawing ### {#render-pass-encoder-drawing}

<dl dfn-type=method dfn-for=GPURenderEncoderBase>
    : <dfn>setPipeline(pipeline)</dfn>
    ::
        Sets the current {{GPURenderPipeline}}.

        <div algorithm="GPURenderEncoderBase.setPipeline">
            **Called on:** {{GPURenderEncoderBase}} this.

            **Arguments:**
            <pre class=argumentdef for="GPURenderEncoderBase/setPipeline(pipeline)">
                |pipeline|: The render pipeline to use for subsequent drawing commands.
            </pre>

            **Returns:** void

            Issue the following steps on the [=Device timeline=] of |this|.{{GPUObjectBase/[[device]]}}:
            <div class=device-timeline>
                1. If any of the following conditions are unsatisfied, make |this| [=invalid=] and stop.
                    <div class=validusage>
                        - |pipeline| is [$valid to use with$] |this|.

                        Issue: Validate that |pipeline| is compatible with the render pass descriptor.
                    </div>
                1. Set |this|.{{GPURenderEncoderBase/[[pipeline]]}} to be |pipeline|.
            </div>
        </div>

    : <dfn>setIndexBuffer(buffer, indexFormat, offset, size)</dfn>
    ::
        Sets the current index buffer.

        <div algorithm="GPURenderEncoderBase.setIndexBuffer">
            **Called on:** {{GPURenderEncoderBase}} this.

            **Arguments:**
            <pre class=argumentdef for="GPURenderEncoderBase/setIndexBuffer(buffer, indexFormat, offset, size)">
                |buffer|: Buffer containing index data to use for subsequent drawing commands.
                |indexFormat|: Format of the index data contained in |buffer|.
                |offset|: Offset in bytes into |buffer| where the index data begins.
                |size|: Size in bytes of the index data in |buffer|.
                    If `0`, |buffer|.{{GPUBuffer/[[size]]}} - |offset| is used.
            </pre>

            **Returns:** void

            Issue the following steps on the [=Device timeline=] of |this|.{{GPUObjectBase/[[device]]}}:
            <div class=device-timeline>
                1. If any of the following conditions are unsatisfied, make |this| [=invalid=] and stop.
                    <div class=validusage>
                        - |buffer| is [$valid to use with$] |this|.
                        - |buffer|.{{GPUBuffer/[[usage]]}} contains {{GPUBufferUsage/INDEX}}.
                        - |offset| + |size| &le; |buffer|.{{GPUBuffer/[[size]]}}.
                    </div>
                1. Add |buffer| to the [=usage scope=] as {{GPUBufferUsage/INDEX}}.
                1. Set |this|.{{GPURenderEncoderBase/[[index_buffer]]}} to be |buffer|.
                1. Set |this|.{{GPURenderEncoderBase/[[index_format]]}} to be |indexFormat|.
            </div>
        </div>

    : <dfn>setVertexBuffer(slot, buffer, offset, size)</dfn>
    ::
        Sets the current vertex buffer for the given slot.

        <div algorithm="GPURenderEncoderBase.setVertexBuffer">
            **Called on:** {{GPURenderEncoderBase}} this.

            **Arguments:**
            <pre class=argumentdef for="GPURenderEncoderBase/setVertexBuffer(slot, buffer, offset, size)">
                |slot|: The vertex buffer slot to set the vertex buffer for.
                |buffer|: Buffer containing vertex data to use for subsequent drawing commands.
                |offset|: Offset in bytes into |buffer| where the vertex data begins.
                |size|: Size in bytes of the vertex data in |buffer|.
                    If `0`, |buffer|.{{GPUBuffer/[[size]]}} - |offset| is used.
            </pre>

            **Returns:** void

            Issue the following steps on the [=Device timeline=] of |this|.{{GPUObjectBase/[[device]]}}:
            <div class=device-timeline>
                1. If any of the following conditions are unsatisfied, make |this| [=invalid=] and stop.
                    <div class=validusage>
                        - |buffer| is [$valid to use with$] |this|.
                        - |buffer|.{{GPUBuffer/[[usage]]}} contains {{GPUBufferUsage/VERTEX}}.
                        - |slot| &lt; [=maximum number of vertex buffers=].
                        - |offset| + |size| &le; |buffer|.{{GPUBuffer/[[size]]}}.

                        Issue: Define the <dfn dfn for=>maximum number of vertex buffers</dfn>.
                    </div>
                1. Add |buffer| to the [=usage scope=] as {{GPUBufferUsage/VERTEX}}.
                1. Set |this|.{{GPURenderEncoderBase/[[vertex_buffers]]}}[|slot|] to be |buffer|.
            </div>
        </div>

    : <dfn>draw(vertexCount, instanceCount, firstVertex, firstInstance)</dfn>
    ::
        Draws primitives.

        <div algorithm="GPURenderEncoderBase.draw">
            **Called on:** {{GPURenderEncoderBase}} this.

            **Arguments:**
            <pre class=argumentdef for="GPURenderEncoderBase/draw(vertexCount, instanceCount, firstVertex, firstInstance)">
                vertexCount: The number of vertices to draw.
                instanceCount: The number of instances to draw.
                firstVertex: Offset into the vertex buffers, in vertices, to begin drawing from.
                firstInstance: First instance to draw.
            </pre>

            **Returns:** void

            Issue: Describe {{GPURenderEncoderBase/draw()}} algorithm steps.
        </div>

    : <dfn>drawIndexed(indexCount, instanceCount, firstIndex, baseVertex, firstInstance)</dfn>
    ::
        Draws indexed primitives.

        <div algorithm="GPURenderEncoderBase.drawIndexed">
            **Called on:** {{GPURenderEncoderBase}} this.

            **Arguments:**
            <pre class=argumentdef for="GPURenderEncoderBase/drawIndexed(indexCount, instanceCount, firstIndex, baseVertex, firstInstance)">
                indexCount: The number of indices to draw.
                instanceCount: The number of instances to draw.
                firstIndex: Offset into the index buffer, in indices, begin drawing from.
                baseVertex: Added to each index value before indexing into the vertex buffers.
                firstInstance: First instance to draw.
            </pre>

            **Returns:** void

            Issue: Describe {{GPURenderEncoderBase/drawIndexed()}} algorithm steps.
        </div>

    : <dfn>drawIndirect(indirectBuffer, indirectOffset)</dfn>
    ::
        Draws primitives using parameters read from a {{GPUBuffer}}.

        The <dfn dfn for=>indirect draw parameters</dfn> encoded in the buffer must be a tightly
        packed block of **four 32-bit unsigned integer values (16 bytes total)**, given in the same
        order as the arguments for {{GPURenderEncoderBase/draw()}}. For example:

        ```js
        let drawIndirectParameters = new Uint32Array(4);
        drawIndirectParameters[0] = vertexCount;
        drawIndirectParameters[1] = instanceCount;
        drawIndirectParameters[2] = firstVertex;
        drawIndirectParameters[3] = firstInstance;
        ```

        <div algorithm="GPURenderEncoderBase.drawIndirect">
            **Called on:** {{GPURenderEncoderBase}} this.

            **Arguments:**
            <pre class=argumentdef for="GPURenderEncoderBase/drawIndirect(indirectBuffer, indirectOffset)">
                |indirectBuffer|: Buffer containing the [=indirect draw parameters=].
                |indirectOffset|: Offset in bytes into |indirectBuffer| where the drawing data begins.
            </pre>

            **Returns:** void

            Issue the following steps on the [=Device timeline=] of |this|.{{GPUObjectBase/[[device]]}}:
            <div class=device-timeline>
                1. If any of the following conditions are unsatisfied, make |this| [=invalid=] and stop.
                    <div class=validusage>
                        - |indirectBuffer| is [$valid to use with$] |this|.
                        - |indirectBuffer|.{{GPUBuffer/[[usage]]}} contains {{GPUBufferUsage/INDIRECT}}.
                        - |indirectOffset| + sizeof([=indirect draw parameters=]) &le;
                            |indirectBuffer|.{{GPUBuffer/[[size]]}}.
                        - |indirectOffset| is a multiple of 4.
                    </div>
                1. Add |indirectBuffer| to the [=usage scope=] as {{GPUBufferUsage/INDIRECT}}.
            </div>
        </div>

    : <dfn>drawIndexedIndirect(indirectBuffer, indirectOffset)</dfn>
    ::
        Draws indexed primitives using parameters read from a {{GPUBuffer}}.

        The <dfn dfn for=>indirect drawIndexed parameters</dfn> encoded in the buffer must be a
        tightly packed block of **five 32-bit unsigned integer values (20 bytes total)**, given in
        the same order as the arguments for {{GPURenderEncoderBase/drawIndexed()}}. For example:

        ```js
        let drawIndexedIndirectParameters = new Uint32Array(5);
        drawIndexedIndirectParameters[0] = indexCount;
        drawIndexedIndirectParameters[1] = instanceCount;
        drawIndexedIndirectParameters[2] = firstIndex;
        drawIndexedIndirectParameters[3] = baseVertex;
        drawIndexedIndirectParameters[4] = firstInstance;
        ```

        <div algorithm="GPURenderEncoderBase.drawIndexedIndirect">
            **Called on:** {{GPURenderEncoderBase}} this.

            **Arguments:**
            <pre class=argumentdef for="GPURenderEncoderBase/drawIndexedIndirect(indirectBuffer, indirectOffset)">
                |indirectBuffer|: Buffer containing the [=indirect drawIndexed parameters=].
                |indirectOffset|: Offset in bytes into |indirectBuffer| where the drawing data begins.
            </pre>

            **Returns:** void

            Issue the following steps on the [=Device timeline=] of |this|.{{GPUObjectBase/[[device]]}}:
            <div class=device-timeline>
                1. If any of the following conditions are unsatisfied, make |this| [=invalid=] and stop.
                    <div class=validusage>
                        - |indirectBuffer| is [$valid to use with$] |this|.
                        - |indirectBuffer|.{{GPUBuffer/[[usage]]}} contains {{GPUBufferUsage/INDIRECT}}.
                        - |indirectOffset| + sizeof([=indirect drawIndexed parameters=]) &le;
                            |indirectBuffer|.{{GPUBuffer/[[size]]}}.
                        - |indirectOffset| is a multiple of 4.
                    </div>
                1. Add |indirectBuffer| to the [=usage scope=] as {{GPUBufferUsage/INDIRECT}}.
            </div>
        </div>
</dl>

### Rasterization state ### {#render-pass-encoder-rasterization-state}

The {{GPURenderPassEncoder}} has several methods which affect how draw commands are rasterized to
attachments used by this encoder.

<dl dfn-type=method dfn-for=GPURenderPassEncoder>
    : <dfn>setViewport(x, y, width, height, minDepth, maxDepth)</dfn>
    ::

        Sets the viewport used during the rasterization stage to linearly map from normalized device
        coordinates to viewport coordinates.

        <div algorithm="GPURenderPassEncoder.setViewport">
            **Called on:** {{GPURenderPassEncoder}} |this|.

            **Arguments:**
            <pre class=argumentdef for="GPURenderPassEncoder/setViewport(x, y, width, height, minDepth, maxDepth)">
                |x|: Minimum X value of the viewport in pixels.
                |y|: Minimum Y value of the viewport in pixels.
                |width|: Width of the viewport in pixels.
                |height|: Height of the viewport in pixels.
                |minDepth|: Minimum depth value of the viewport.
                |maxDepth|: Maximum depth value of the viewport.
            </pre>

            **Returns:** void

            Issue the following steps on the [=Device timeline=] of |this|:
            <div class=device-timeline>
                1. If any of the following conditions are unsatisfied, generate a validation
                    error and stop.
                    <div class=validusage>
                        - |width| is greater than `0`.
                        - |height| is greater than `0`.
                        - |minDepth| is greater than or equal to `0.0` and less than or equal to `1.0`.
                        - |maxDepth| is greater than or equal to `0.0` and less than or equal to `1.0`.
                    </div>
                1. Set the viewport to the extents |x|, |y|, |width|, |height|, |minDepth|, and |maxDepth|.
            </div>

            Issue: Allowed for GPUs to use fixed point or rounded viewport coordinates
        </div>

    : <dfn>setScissorRect(x, y, width, height)</dfn>
    ::

        Sets the scissor rectangle used during the rasterization stage.
        After transformation into viewport coordinates any fragments which fall outside the scissor
        rectangle will be discarded.

        <div algorithm="GPURenderPassEncoder.setScissorRect">
            **Called on:** {{GPURenderPassEncoder}} |this|.

            **Arguments:**
            <pre class=argumentdef for="GPURenderPassEncoder/setScissorRect(x, y, width, height)">
                |x|: Minimum X value of the scissor rectangle in pixels.
                |y|: Minimum Y value of the scissor rectangle in pixels.
                |width|: Width of the scissor rectangle in pixels.
                |height|: Height of the scissor rectangle in pixels.
            </pre>

            **Returns:** void

            Issue the following steps on the [=Device timeline=] of |this|:
            <div class=device-timeline>
                1. If any of the following conditions are unsatisfied, generate a validation
                    error and stop.
                    <div class=validusage>
                        - |x| is greater than or equal to `0`.
                        - |y| is greater than or equal to `0`.
                        - |width| is greater than `0`.
                        - |height| is greater than `0`.
                        - |x|+|width| is less than or equal to
                            |this|.{{GPURenderPassEncoder/[[attachment_size]]}}.width.
                        - |y|+|height| is less than or equal to
                            |this|.{{GPURenderPassEncoder/[[attachment_size]]}}.height.
                    </div>
                1. Set the scissor rectangle to the extents |x|, |y|, |width|, and |height|.
            </div>
        </div>

    : <dfn>setBlendColor(color)</dfn>
    ::

        Sets the constant blend color and alpha values used with {{GPUBlendFactor/"blend-color"}}
        and {{GPUBlendFactor/"one-minus-blend-color"}} {{GPUBlendFactor}}s.

        <div algorithm="GPURenderPassEncoder.setBlendColor">
            **Called on:** {{GPURenderPassEncoder}} this.

            **Arguments:**
            <pre class=argumentdef for="GPURenderPassEncoder/setBlendColor(color)">
                color:
            </pre>
        </div>

    : <dfn>setStencilReference(reference)</dfn>
    ::

        Sets the stencil reference value used during stencil tests with the the
        {{GPUStencilOperation/"replace"}} {{GPUStencilOperation}}.

        <div algorithm="GPURenderPassEncoder.setStencilReference">
            **Called on:** {{GPURenderPassEncoder}} this.

            **Arguments:**
            <pre class=argumentdef for="GPURenderPassEncoder/setStencilReference(reference)">
                reference:
            </pre>
        </div>
</dl>

### Queries ### {#render-pass-encoder-queries}

<dl dfn-type=method dfn-for=GPURenderPassEncoder>
    : <dfn>beginOcclusionQuery(queryIndex)</dfn>
    ::

        <div algorithm="GPURenderPassEncoder.beginOcclusionQuery">
            **Called on:** {{GPURenderPassEncoder}} this.

            **Arguments:**
            <pre class=argumentdef for="GPURenderPassEncoder/beginOcclusionQuery(queryIndex)">
                queryIndex:
            </pre>

            **Returns:** void

            Issue: Describe {{GPURenderPassEncoder/beginOcclusionQuery()}} algorithm steps.
        </div>

    : <dfn>endOcclusionQuery()</dfn>
    ::

        <div algorithm="GPURenderPassEncoder.endOcclusionQuery">
            **Called on:** {{GPURenderPassEncoder}} this.

            **Returns:** void

            Issue: Describe {{GPURenderPassEncoder/endOcclusionQuery()}} algorithm steps.
        </div>

    : <dfn>beginPipelineStatisticsQuery(querySet, queryIndex)</dfn>
    ::

        <div algorithm="GPURenderPassEncoder.beginPipelineStatisticsQuery">
            **Called on:** {{GPURenderPassEncoder}} this.

            **Arguments:**
            <pre class=argumentdef for="GPURenderPassEncoder/beginPipelineStatisticsQuery(querySet, queryIndex)">
                querySet:
                queryIndex:
            </pre>

            **Returns:** void

            Issue: Describe {{GPURenderPassEncoder/beginPipelineStatisticsQuery()}} algorithm steps.
        </div>

    : <dfn>endPipelineStatisticsQuery()</dfn>
    ::

        <div algorithm="GPURenderPassEncoder.endPipelineStatisticsQuery">
            **Called on:** {{GPURenderPassEncoder}} this.

            **Returns:** void

            Issue: Describe {{GPURenderPassEncoder/endPipelineStatisticsQuery()}} algorithm steps.
        </div>

    : <dfn>writeTimestamp(querySet, queryIndex)</dfn>
    ::

        <div algorithm="GPURenderPassEncoder.writeTimestamp">
            **Called on:** {{GPURenderPassEncoder}} this.

            **Arguments:**
            <pre class=argumentdef for="GPURenderPassEncoder/writeTimestamp(querySet, queryIndex)">
                querySet:
                queryIndex:
            </pre>

            **Returns:** void

            Issue: Describe {{GPURenderPassEncoder/writeTimestamp()}} algorithm steps.
        </div>
</dl>

### Bundles ### {#render-pass-encoder-bundles}

<dl dfn-type=method dfn-for=GPURenderPassEncoder>
    : <dfn>executeBundles(bundles)</dfn>
    ::

        <div algorithm="GPURenderPassEncoder.executeBundles">
            **Called on:** {{GPURenderPassEncoder}} this.

            **Arguments:**
            <pre class=argumentdef for="GPURenderPassEncoder/executeBundles(bundles)">
                bundles:
            </pre>

            **Returns:** void

            Issue: Describe {{GPURenderPassEncoder/executeBundles()}} algorithm steps.
        </div>
</dl>

### Finalization ### {#render-pass-encoder-finalization}

The render pass encoder can be ended by calling {{GPURenderPassEncoder/endPass()}} once the user
has finished recording commands for the pass. Once {{GPURenderPassEncoder/endPass()}} has been
called the render pass encoder can no longer be used.

<dl dfn-type=method dfn-for=GPURenderPassEncoder>
    : <dfn>endPass()</dfn>
    ::

        Completes recording of the compute pass commands sequence.

        <div algorithm="GPURenderPassEncoder.endPass">
            **Called on:** {{GPURenderPassEncoder}} |this|.

            **Returns:** void

            Issue the following steps on the [=Device timeline=] of |this|:
            <div class=device-timeline>
                1. If any of the following conditions are unsatisfied, generate a validation
                    error and stop.
                    <div class=validusage>
                        - |this|.{{GPUProgrammablePassEncoder/[[debug_group_stack]]}}.length is 0.
                    </div>

                Issue: Add remaining validation.
            </div>
        </div>
</dl>

# Bundles # {#bundles}

## GPURenderBundle ## {#render-bundle}

<script type=idl>
interface GPURenderBundle {
};
GPURenderBundle includes GPUObjectBase;
</script>

### Creation ### {#render-bundle-creation}

<script type=idl>
dictionary GPURenderBundleDescriptor : GPUObjectDescriptorBase {
};
</script>

<script type=idl>
interface GPURenderBundleEncoder {
    GPURenderBundle finish(optional GPURenderBundleDescriptor descriptor = {});
};
GPURenderBundleEncoder includes GPUObjectBase;
GPURenderBundleEncoder includes GPUProgrammablePassEncoder;
GPURenderBundleEncoder includes GPURenderEncoderBase;
</script>

<dl dfn-type=method dfn-for=GPUDevice>
    : <dfn>createRenderBundleEncoder(descriptor)</dfn>
    ::
        Creates a new {{GPURenderBundleEncoder}}.

        <div algorithm=GPUDevice.createRenderBundleEncoder>
            **Called on:** {{GPUDevice}} this.

            **Arguments:**
            <pre class=argumentdef for="GPUDevice/createRenderBundleEncoder(descriptor)">
                descriptor:
            </pre>

            **Returns:** {{GPURenderBundleEncoder}}

            Issue: Describe {{GPUDevice/createRenderBundleEncoder()}} algorithm steps.
        </div>
</dl>

### Encoding ### {#render-bundle-encoding}

<script type=idl>
dictionary GPURenderBundleEncoderDescriptor : GPUObjectDescriptorBase {
    required sequence<GPUTextureFormat> colorFormats;
    GPUTextureFormat depthStencilFormat;
    GPUSize32 sampleCount = 1;
};
</script>

### Finalization ### {#render-bundle-finalization}

<dl dfn-type=method dfn-for=GPURenderBundleEncoder>
    : <dfn>finish(descriptor)</dfn>
    ::

        <div algorithm="GPURenderBundleEncoder.finish">
            **Called on:** {{GPURenderBundleEncoder}} this.

            **Arguments:**
            <pre class=argumentdef for="GPURenderBundleEncoder/finish(descriptor)">
                descriptor:
            </pre>

            **Returns:** {{GPURenderBundle}}

            Issue: Describe {{GPURenderBundleEncoder/finish()}} algorithm steps.
        </div>
</dl>

# Queues # {#queues}

<script type=idl>
interface GPUQueue {
    void submit(sequence<GPUCommandBuffer> commandBuffers);

    GPUFence createFence(optional GPUFenceDescriptor descriptor = {});
    void signal(GPUFence fence, GPUFenceValue signalValue);

    void writeBuffer(
        GPUBuffer buffer,
        GPUSize64 bufferOffset,
        [AllowShared] BufferSource data,
        optional GPUSize64 dataOffset = 0,
        optional GPUSize64 size);

    void writeTexture(
      GPUTextureCopyView destination,
      [AllowShared] BufferSource data,
      GPUTextureDataLayout dataLayout,
      GPUExtent3D size);

    void copyImageBitmapToTexture(
        GPUImageBitmapCopyView source,
        GPUTextureCopyView destination,
        GPUExtent3D copySize);
};
GPUQueue includes GPUObjectBase;
</script>

{{GPUQueue}} has the following methods:

<dl dfn-type=method dfn-for=GPUQueue>
    : <dfn>writeBuffer(buffer, bufferOffset, data, dataOffset, size)</dfn>
    ::
        Issues a write operation of the provided data into a {{GPUBuffer}}.

        <div algorithm=GPUQueue.writeBuffer>
            **Called on:** {{GPUQueue}} |this|.

            **Arguments:**
            <pre class=argumentdef for="GPUQueue/writeBuffer(buffer, bufferOffset, data, dataOffset, size)">
                |buffer|:
                |bufferOffset|:
                |data|:
                |dataOffset|:
                |size|:
            </pre>

            **Returns:** `void`

            1. If |data| is an {{ArrayBuffer}} or {{DataView}}, let the element type be "byte".
                Otherwise, |data| is a TypedArray; let the element type be the type of the TypedArray.
            1. Let |dataSize| be the size of |data|, in elements.
            1. If |size| is unspecified,
                let |contentsSize| be |dataSize| &minus; |dataOffset|.
                Otherwise, let |contentsSize| be |size|.
            1. If any of the following conditions are unsatisfied,
                throw {{OperationError}} and stop.
                <!-- Note: it's easiest to write the valid usage rules inline
                     here, because they depend on contentsSize above. -->
                <div class=validusage>
                    - |contentsSize| &ge; 0.
                    - |dataOffset| + |contentsSize| &le; |dataSize|.
                    - |contentsSize|, converted to bytes, is a multiple of 4 bytes.
                </div>
            1. Let |dataContents| be [=get a copy of the buffer source|a copy of the bytes held by the buffer source=].
            1. Let |contents| be the |contentsSize| elements of |dataContents| starting at
                an offset of |dataOffset| elements.
            1. Issue the following steps on the [=Queue timeline=] of |this|:
                <div class=queue-timeline>
                    1. If any of the following conditions are unsatisfied,
                        generate a validation error and stop.
                        <div class=validusage>
                            - |buffer| is [$valid to use with$] |this|.
                            - |buffer|.{{GPUBuffer/[[state]]}} is [=buffer state/unmapped=].
                            - |buffer|.{{GPUBuffer/[[usage]]}} includes {{GPUBufferUsage/COPY_DST}}.
                            - |bufferOffset|, converted to bytes, is a multiple of 4 bytes.
                            - |bufferOffset| + |contentsSize|, converted to bytes, &le; |buffer|.{{GPUBuffer/[[size]]}} bytes.
                        </div>
                    1. Write |contents| into |buffer| starting at |bufferOffset|.
                </div>
        </div>

    : <dfn>writeTexture(destination, data, dataLayout, size)</dfn>
    ::
        Issues a write operation of the provided data into a {{GPUTexture}}.

        <div algorithm=GPUQueue.writeTexture>
            **Called on:** {{GPUQueue}} |this|.

            **Arguments:**
            <pre class=argumentdef for="GPUQueue/writeTexture(destination, data, dataLayout, size)">
                |destination|:
                |data|:
                |dataLayout|:
                |size|:
            </pre>

            **Returns:** `void`

            1. Let |dataBytes| be [=get a copy of the buffer source|a copy of the bytes held by the buffer source=] |data|.
            1. Let |dataByteSize| be the number of bytes in |dataBytes|.
            1. If any of the following conditions are unsatisfied,
                throw {{OperationError}} and stop.
                <div class=validusage>
                    - [$validating linear texture data$](|dataLayout|,
                        |dataByteSize|,
                        |destination|.{{GPUTextureCopyView/texture}}.{{GPUTexture/[[format]]}},
                        |size|) succeeds.
                </div>
            1. Let |contents| be the contents of the [=images=] seen by
                viewing |dataBytes| with |dataLayout| and |size|.

                Issue: Specify more formally.
            1. Issue the following steps on the [=Queue timeline=] of |this|:
                <div class=queue-timeline>
                    1. If any of the following conditions are unsatisfied,
                        generate a validation error and stop.
                        <div class=validusage>
                            - [$validating GPUTextureCopyView$](|destination|) returns true.
                            - |destination|.{{GPUTextureCopyView/texture}}.{{GPUTexture/[[textureUsage]]}}
                                includes {{GPUTextureUsage/COPY_DST}}.
                            - |destination|.{{GPUTextureCopyView/texture}}.{{GPUTexture/[[sampleCount]]}} is 1.
                            - [=Valid Texture Copy Range=](|destination|, |size|)
                                is satisfied.

                            Note: unlike
                            {{GPUCommandEncoder}}.{{GPUCommandEncoder/copyBufferToTexture()}},
                            there is no alignment requirement on
                            |dataLayout|.{{GPUTextureDataLayout/bytesPerRow}}.
                        </div>
                    1. Write |contents| into |destination|.

                        Issue: Specify more formally.
                </div>
        </div>

    : <dfn>copyImageBitmapToTexture(source, destination, copySize)</dfn>
    ::
        Schedules a copy operation of the contents of an image bitmap into the destination texture.

        <div algorithm=GPUQueue.copyImageBitmapToTexture>
            **Called on:** {{GPUQueue}} this.

            **Arguments:**
            <pre class=argumentdef for="GPUQueue/copyImageBitmapToTexture(source, destination, copySize)">
                source:
                |destination|:
                |copySize|:
            </pre>

            **Returns:** `void`

            If any of the following conditions are unsatisfied, throw an {{OperationError}} and stop.
            <div class=validusage>
                - |copySize|.[=Extent3D/depth=] is `1`.
                - |destination|.{{GPUTextureCopyView/texture}}.{{GPUTexture/[[format]]}} is one of the following:
                    - {{GPUTextureFormat/"rgba8unorm"}}
                    - {{GPUTextureFormat/"rgba8unorm-srgb"}}
                    - {{GPUTextureFormat/"bgra8unorm"}}
                    - {{GPUTextureFormat/"bgra8unorm-srgb"}}
                    - {{GPUTextureFormat/"rgb10a2unorm"}}
                    - {{GPUTextureFormat/"rgba16float"}}
                    - {{GPUTextureFormat/"rgba32float"}}
                    - {{GPUTextureFormat/"rg8unorm"}}
                    - {{GPUTextureFormat/"rg16float"}}
            </div>
        </div>

    : <dfn>submit(commandBuffers)</dfn>
    ::
        Schedules the execution of the command buffers by the GPU on this queue.

        <div algorithm=GPUQueue.submit>
            **Called on:** {{GPUQueue}} this.

            **Arguments:**
            <pre class=argumentdef for="GPUQueue/submit(commandBuffers)">
                |commandBuffers|:
            </pre>

            **Returns:** `void`

            If any of the following conditions are unsatisfied, generate a validation error and stop.
            <div class=validusage>
                - Every {{GPUBuffer}} referenced in any element of |commandBuffers| is in the
                    `"unmapped"` [=buffer state=].
                - Every [=usage scope=] contained in |commandBuffers| satisfies the [=usage scope validation=].
            </div>
        </div>
</dl>

## GPUFence ## {#fence}

<script type=idl>
interface GPUFence {
    GPUFenceValue getCompletedValue();
    Promise<void> onCompletion(GPUFenceValue completionValue);
};
GPUFence includes GPUObjectBase;
</script>

### Creation ### {#fence-creation}

<script type=idl>
dictionary GPUFenceDescriptor : GPUObjectDescriptorBase {
    GPUFenceValue initialValue = 0;
};
</script>

<dl dfn-type=method dfn-for=GPUQueue>
    : <dfn>createFence(descriptor)</dfn>
    ::

        <div algorithm="GPUQueue.createFence">
            **Called on:** {{GPUQueue}} this.

            **Arguments:**
            <pre class=argumentdef for="GPUQueue/createFence(descriptor)">
                descriptor:
            </pre>

            **Returns:** {{GPUFence}}

            Issue: Describe {{GPUQueue/createFence()}} algorithm steps.
        </div>
</dl>

### Completion ### {#fence-signaling}

Completion of a fence is signaled from the {{GPUQueue}} that created it.

<dl dfn-type=method dfn-for=GPUQueue>
    : <dfn>signal(fence, signalValue)</dfn>
    ::

        <div algorithm="GPUQueue.signal">
            **Called on:** {{GPUQueue}} this.

            **Arguments:**
            <pre class=argumentdef for="GPUQueue/signal(fence, signalValue)">
                fence:
                signalValue:
            </pre>

            **Returns:** void

            Issue: Describe {{GPUQueue/signal()}} algorithm steps.
        </div>
</dl>

The completion of the fence and the value it completes with can be observed from the {{GPUFence}}.

<dl dfn-type=method dfn-for=GPUFence>
    : <dfn>getCompletedValue()</dfn>
    ::

        <div algorithm="GPUFence.getCompletedValue">
            **Called on:** {{GPUFence}} this.

            **Returns:** {{GPUFenceValue}}

            Issue: Describe {{GPUFence/getCompletedValue()}} algorithm steps.
        </div>

    : <dfn>onCompletion(completionValue)</dfn>
    ::

        <div algorithm="GPUFence.onCompletion">
            **Called on:** {{GPUFence}} this.

            **Arguments:**
            <pre class=argumentdef for="GPUFence/onCompletion(completionValue)">
                completionValue:
            </pre>

            **Returns:** {{Promise}}

            Issue: Describe {{GPUFence/onCompletion()}} algorithm steps.
        </div>
</dl>


Queries {#queries}
================

## QuerySet ## {#queryset}

<script type=idl>
interface GPUQuerySet {
    void destroy();
};
GPUQuerySet includes GPUObjectBase;
</script>

### Creation ### {#queryset-creation}

<script type=idl>
dictionary GPUQuerySetDescriptor : GPUObjectDescriptorBase {
    required GPUQueryType type;
    required GPUSize32 count;
    sequence<GPUPipelineStatisticName> pipelineStatistics = [];
};
</script>

<dl dfn-type=dict-member dfn-for=GPUQuerySetDescriptor>
    : <dfn>pipelineStatistics</dfn>
    ::
        The set of {{GPUPipelineStatisticName}} values in this sequence defines which pipeline statistics will be returned in the new query set.

        <div class=validusage dfn-for=GPUQuerySetDescriptor.pipelineStatistics>
            <dfn abstract-op>Valid Usage</dfn>

            1. |pipelineStatistics| is ignored if type is not {{GPUQueryType/pipeline-statistics}}.
            2. If {{GPUExtensionName/pipeline-statistics-query}} is not available, |type| must not be {{GPUQueryType/pipeline-statistics}}.
            3. If |type| is {{GPUQueryType/pipeline-statistics}},  |pipelineStatistics| must be a sequence of {{GPUPipelineStatisticName}} values which cannot be duplicated.
        </div>
</dl>

<dl dfn-type=method dfn-for=GPUDevice>
    : <dfn>createQuerySet(descriptor)</dfn>
    ::
        Creates a new {{GPUQuerySet}}.

        <div algorithm=GPUDevice.createQuerySet>
            **Called on:** {{GPUDevice}} this.

            **Arguments:**
            <pre class=argumentdef for="GPUDevice/createQuerySet(descriptor)">
                descriptor:
            </pre>

            **Returns:** {{GPUQuerySet}}

            Issue: Describe {{GPUDevice/createQuerySet()}} algorithm steps.
        </div>
</dl>

### Finalization ### {#queryset-finalization}

<dl dfn-type=method dfn-for=GPUQuerySet>
    : <dfn>destroy()</dfn>
    ::

        <div algorithm="GPUQuerySet.signal">
            **Called on:** {{GPUQuerySet}} this.

            **Returns:** void

            Issue: Describe {{GPUQuerySet/destroy()}} algorithm steps.
        </div>
</dl>

## QueryType ## {#querytype}

<script type=idl>
enum GPUQueryType {
    "occlusion",
    "pipeline-statistics",
    "timestamp"
};
</script>

## Pipeline Statistics Query ## {#pipeline-statistics}

<script type=idl>
enum GPUPipelineStatisticName {
    "vertex-shader-invocations",
    "clipper-invocations",
    "clipper-primitives-out",
    "fragment-shader-invocations",
    "compute-shader-invocations"
};
</script>

When resolving pipeline statistics query, each result is written into {{GPUSize64}}, and the number and order of the results written to GPU buffer matches the number and order of {{GPUPipelineStatisticName}} specified in {{GPUQuerySetDescriptor/pipelineStatistics}}.

The {{GPURenderPassEncoder/beginPipelineStatisticsQuery()}} and {{GPURenderPassEncoder/endPipelineStatisticsQuery()}} (on both {{GPUComputePassEncoder}} and {{GPURenderPassEncoder}}) cannot be nested. A pipeline statistics query must be ended before beginning another one.

Pipeline statistics query requires {{GPUExtensionName/pipeline-statistics-query}} is available on the device.

## Timestamp Query ## {#timestamp}

Timestamp query allows application to write timestamp values to a {{GPUQuerySet}} by calling {{GPURenderPassEncoder/writeTimestamp()}} on {{GPUComputePassEncoder}} or {{GPURenderPassEncoder}} or {{GPUCommandEncoder}}, and then resolve timestamp values in **nanoseconds** (type of {{GPUSize64}}) to a {{GPUBuffer}} (using {{GPUCommandEncoder/resolveQuerySet()}}).

Timestamp query requires {{GPUExtensionName/timestamp-query}} is available on the device.

Note: The timestamp values may be zero if the physical device reset timestamp counter, please ignore it and the following values.

Issue: Write normative text about timestamp value resets.

Issue: Because timestamp query provides high-resolution GPU timestamp, we need to decide what constraints, if any, are on its availability.

# Canvas Rendering &amp; Swap Chains # {#canvas-rendering}

<script type=idl>
interface GPUCanvasContext {
    GPUSwapChain configureSwapChain(GPUSwapChainDescriptor descriptor);

    Promise<GPUTextureFormat> getSwapChainPreferredFormat(GPUDevice device);
};
</script>

<dl dfn-type=method dfn-for=GPUCanvasContext>
    : <dfn>configureSwapChain(descriptor)</dfn>
    ::
        Configures the swap chain for this canvas, and returns a new
        {{GPUSwapChain}} object representing it. Destroys any swapchain
        previously returned by `configureSwapChain`, including all of the
        textures it has produced.

        <div algorithm="GPUCanvasContext.configureSwapChain">
            **Called on:** {{GPUCanvasContext}} this.

            **Arguments:**
            <pre class=argumentdef for="GPUCanvasContext/configureSwapChain(descriptor)">
                descriptor:
            </pre>

            **Returns:** {{GPUSwapChain}}

            Issue: Describe {{GPUCanvasContext/configureSwapChain()}} algorithm steps.
        </div>

    : <dfn>getSwapChainPreferredFormat(device)</dfn>
    ::

        <div algorithm="GPUCanvasContext.getSwapChainPreferredFormat">
            **Called on:** {{GPUCanvasContext}} this.

            **Arguments:**
            <pre class=argumentdef for="GPUCanvasContext/getSwapChainPreferredFormat(device)">
                device:
            </pre>

            **Returns:** Promise<{{GPUTextureFormat}}>

            Issue: Describe {{GPUCanvasContext/getSwapChainPreferredFormat()}} algorithm steps.
        </div>
</dl>

<script type=idl>
dictionary GPUSwapChainDescriptor : GPUObjectDescriptorBase {
    required GPUDevice device;
    required GPUTextureFormat format;
    GPUTextureUsageFlags usage = 0x10;  // GPUTextureUsage.OUTPUT_ATTACHMENT
};
</script>

<script type=idl>
interface GPUSwapChain {
    GPUTexture getCurrentTexture();
};
GPUSwapChain includes GPUObjectBase;
</script>

In the "update the rendering [of the] `Document`" step of the "Update the rendering" HTML processing
model, the contents of the {{GPUTexture}} most recently returned by
{{GPUSwapChain/getCurrentTexture()}} are used to update the rendering for the `canvas`, and it is as
if {{GPUTexture/destroy()}} were called on it (making it unusable elsewhere in WebGPU).

Before this drawing buffer is presented for compositing, the implementation shall ensure that all
rendering operations have been flushed to the drawing buffer.

<dl dfn-type=method dfn-for=GPUSwapChain>
    : <dfn>getCurrentTexture()</dfn>
    ::

        <div algorithm="GPUSwapChain.getCurrentTexture">
            **Called on:** {{GPUSwapChain}} this.

            **Returns:** {{GPUTexture}}

            Issue: Describe {{GPUSwapChain/getCurrentTexture()}} algorithm steps.
        </div>
</dl>

# Errors &amp; Debugging # {#errors-and-debugging}

## Fatal Errors ## {#fatal-errors}

<script type=idl>
interface GPUDeviceLostInfo {
    readonly attribute DOMString message;
};

partial interface GPUDevice {
    readonly attribute Promise<GPUDeviceLostInfo> lost;
};
</script>


## Error Scopes ## {#error-scopes}

<script type=idl>
enum GPUErrorFilter {
    "out-of-memory",
    "validation"
};
</script>

<script type=idl>
interface GPUOutOfMemoryError {
    constructor();
};

interface GPUValidationError {
    constructor(DOMString message);
    readonly attribute DOMString message;
};

typedef (GPUOutOfMemoryError or GPUValidationError) GPUError;
</script>

<script type=idl>
partial interface GPUDevice {
    void pushErrorScope(GPUErrorFilter filter);
    Promise<GPUError?> popErrorScope();
};
</script>

{{GPUDevice/popErrorScope()}} throws {{OperationError}} if there are no error scopes on the stack.
{{GPUDevice/popErrorScope()}} rejects with {{OperationError}} if the device is lost.

## Telemetry ## {#telemetry}

<script type=idl>
[
    Exposed=(Window, DedicatedWorker)
]
interface GPUUncapturedErrorEvent : Event {
    constructor(
        DOMString type,
        GPUUncapturedErrorEventInit gpuUncapturedErrorEventInitDict
    );
    [SameObject] readonly attribute GPUError error;
};

dictionary GPUUncapturedErrorEventInit : EventInit {
    required GPUError error;
};
</script>

<script type=idl>
partial interface GPUDevice {
    [Exposed=(Window, DedicatedWorker)]
    attribute EventHandler onuncapturederror;
};
</script>


# Type Definitions # {#type-definitions}

<script type=idl>
typedef [EnforceRange] unsigned long GPUBufferDynamicOffset;
typedef [EnforceRange] unsigned long long GPUFenceValue;
typedef [EnforceRange] unsigned long GPUStencilValue;
typedef [EnforceRange] unsigned long GPUSampleMask;
typedef [EnforceRange] long GPUDepthBias;

typedef [EnforceRange] unsigned long long GPUSize64;
typedef [EnforceRange] unsigned long GPUIntegerCoordinate;
typedef [EnforceRange] unsigned long GPUIndex32;
typedef [EnforceRange] unsigned long GPUSize32;
typedef [EnforceRange] long GPUSignedOffset32;
</script>

## Colors &amp; Vectors ## {#colors-and-vectors}

<script type=idl>
dictionary GPUColorDict {
    required double r;
    required double g;
    required double b;
    required double a;
};
typedef (sequence<double> or GPUColorDict) GPUColor;
</script>

Note: `double` is large enough to precisely hold 32-bit signed/unsigned
integers and single-precision floats.

<script type=idl>
dictionary GPUOrigin2DDict {
    GPUIntegerCoordinate x = 0;
    GPUIntegerCoordinate y = 0;
};
typedef (sequence<GPUIntegerCoordinate> or GPUOrigin2DDict) GPUOrigin2D;
</script>

<script type=idl>
dictionary GPUOrigin3DDict {
    GPUIntegerCoordinate x = 0;
    GPUIntegerCoordinate y = 0;
    GPUIntegerCoordinate z = 0;
};
typedef (sequence<GPUIntegerCoordinate> or GPUOrigin3DDict) GPUOrigin3D;
</script>

An <dfn dfn>Origin3D</dfn> is a {{GPUOrigin3D}}.
[=Origin3D=] is a spec namespace for the following definitions:
<!-- This is silly, but provides convenient syntax for the spec. -->

<div algorithm="GPUOrigin3D accessors" dfn-for=Origin3D>
    For a given {{GPUOrigin3D}} value |origin|, depending on its type, the syntax:

      - |origin|.<dfn dfn>x</dfn> refers to
        either {{GPUOrigin3DDict}}.{{GPUOrigin3DDict/x}}
        or the first item of the sequence.
      - |origin|.<dfn dfn>y</dfn> refers to
        either {{GPUOrigin3DDict}}.{{GPUOrigin3DDict/y}}
        or the second item of the sequence.
      - |origin|.<dfn dfn>z</dfn> refers to
        either {{GPUOrigin3DDict}}.{{GPUOrigin3DDict/z}}
        or the third item of the sequence.
</div>

<script type=idl>
dictionary GPUExtent3DDict {
    required GPUIntegerCoordinate width;
    required GPUIntegerCoordinate height;
    required GPUIntegerCoordinate depth;
};
typedef (sequence<GPUIntegerCoordinate> or GPUExtent3DDict) GPUExtent3D;
</script>

An <dfn dfn>Extent3D</dfn> is a {{GPUExtent3D}}.
[=Extent3D=] is a spec namespace for the following definitions:
<!-- This is silly, but provides convenient syntax for the spec. -->

<div algorithm="GPUExtent3D accessors" dfn-for=Extent3D>
    For a given {{GPUExtent3D}} value |extent|, depending on its type, the syntax:

      - |extent|.<dfn dfn>width</dfn> refers to
        either {{GPUExtent3DDict}}.{{GPUExtent3DDict/width}}
        or the first item of the sequence.
      - |extent|.<dfn dfn>height</dfn> refers to
        either {{GPUExtent3DDict}}.{{GPUExtent3DDict/height}}
        or the second item of the sequence.
      - |extent|.<dfn dfn>depth</dfn> refers to
        either {{GPUExtent3DDict}}.{{GPUExtent3DDict/depth}}
        or the third item of the sequence.
</div>

# Temporary usages of non-exported dfns # {#temp-dfn-usages}

Eventually all of these should disappear but they are useful to avoid warning while building the specification.

[=vertex buffer=]
